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         isAndroid = /android/.test(ua),
68         isTouch =  (function() {
69             try {
70                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
71                     window.addEventListener('touchstart', function __set_has_touch__ () {
72                         Roo.isTouch = true;
73                         window.removeEventListener('touchstart', __set_has_touch__);
74                     });
75                     return false; // no touch on chrome!?
76                 }
77                 document.createEvent("TouchEvent");  
78                 return true;  
79             } catch (e) {  
80                 return false;  
81             } 
82             
83         })();
84     // remove css image flicker
85         if(isIE && !isIE7){
86         try{
87             document.execCommand("BackgroundImageCache", false, true);
88         }catch(e){}
89     }
90     
91     Roo.apply(Roo, {
92         /**
93          * True if the browser is in strict mode
94          * @type Boolean
95          */
96         isStrict : isStrict,
97         /**
98          * True if the page is running over SSL
99          * @type Boolean
100          */
101         isSecure : isSecure,
102         /**
103          * True when the document is fully initialized and ready for action
104          * @type Boolean
105          */
106         isReady : false,
107         /**
108          * Turn on debugging output (currently only the factory uses this)
109          * @type Boolean
110          */
111         
112         debug: false,
113
114         /**
115          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
116          * @type Boolean
117          */
118         enableGarbageCollector : true,
119
120         /**
121          * True to automatically purge event listeners after uncaching an element (defaults to false).
122          * Note: this only happens if enableGarbageCollector is true.
123          * @type Boolean
124          */
125         enableListenerCollection:false,
126
127         /**
128          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
129          * the IE insecure content warning (defaults to javascript:false).
130          * @type String
131          */
132         SSL_SECURE_URL : "javascript:false",
133
134         /**
135          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
136          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
137          * @type String
138          */
139         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140
141         emptyFn : function(){},
142         
143         /**
144          * Copies all the properties of config to obj if they don't already exist.
145          * @param {Object} obj The receiver of the properties
146          * @param {Object} config The source of the properties
147          * @return {Object} returns obj
148          */
149         applyIf : function(o, c){
150             if(o && c){
151                 for(var p in c){
152                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
153                 }
154             }
155             return o;
156         },
157
158         /**
159          * Applies event listeners to elements by selectors when the document is ready.
160          * The event name is specified with an @ suffix.
161 <pre><code>
162 Roo.addBehaviors({
163    // add a listener for click on all anchors in element with id foo
164    '#foo a@click' : function(e, t){
165        // do something
166    },
167
168    // add the same listener to multiple selectors (separated by comma BEFORE the @)
169    '#foo a, #bar span.some-class@mouseover' : function(){
170        // do something
171    }
172 });
173 </code></pre>
174          * @param {Object} obj The list of behaviors to apply
175          */
176         addBehaviors : function(o){
177             if(!Roo.isReady){
178                 Roo.onReady(function(){
179                     Roo.addBehaviors(o);
180                 });
181                 return;
182             }
183             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184             for(var b in o){
185                 var parts = b.split('@');
186                 if(parts[1]){ // for Object prototype breakers
187                     var s = parts[0];
188                     if(!cache[s]){
189                         cache[s] = Roo.select(s);
190                     }
191                     cache[s].on(parts[1], o[b]);
192                 }
193             }
194             cache = null;
195         },
196
197         /**
198          * Generates unique ids. If the element already has an id, it is unchanged
199          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
200          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
201          * @return {String} The generated Id.
202          */
203         id : function(el, prefix){
204             prefix = prefix || "roo-gen";
205             el = Roo.getDom(el);
206             var id = prefix + (++idSeed);
207             return el ? (el.id ? el.id : (el.id = id)) : id;
208         },
209          
210        
211         /**
212          * Extends one class with another class and optionally overrides members with the passed literal. This class
213          * also adds the function "override()" to the class that can be used to override
214          * members on an instance.
215          * @param {Object} subclass The class inheriting the functionality
216          * @param {Object} superclass The class being extended
217          * @param {Object} overrides (optional) A literal with members
218          * @method extend
219          */
220         extend : function(){
221             // inline overrides
222             var io = function(o){
223                 for(var m in o){
224                     this[m] = o[m];
225                 }
226             };
227             return function(sb, sp, overrides){
228                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
229                     overrides = sp;
230                     sp = sb;
231                     sb = function(){sp.apply(this, arguments);};
232                 }
233                 var F = function(){}, sbp, spp = sp.prototype;
234                 F.prototype = spp;
235                 sbp = sb.prototype = new F();
236                 sbp.constructor=sb;
237                 sb.superclass=spp;
238                 
239                 if(spp.constructor == Object.prototype.constructor){
240                     spp.constructor=sp;
241                    
242                 }
243                 
244                 sb.override = function(o){
245                     Roo.override(sb, o);
246                 };
247                 sbp.override = io;
248                 Roo.override(sb, overrides);
249                 return sb;
250             };
251         }(),
252
253         /**
254          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255          * Usage:<pre><code>
256 Roo.override(MyClass, {
257     newMethod1: function(){
258         // etc.
259     },
260     newMethod2: function(foo){
261         // etc.
262     }
263 });
264  </code></pre>
265          * @param {Object} origclass The class to override
266          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
267          * containing one or more methods.
268          * @method override
269          */
270         override : function(origclass, overrides){
271             if(overrides){
272                 var p = origclass.prototype;
273                 for(var method in overrides){
274                     p[method] = overrides[method];
275                 }
276             }
277         },
278         /**
279          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
280          * <pre><code>
281 Roo.namespace('Company', 'Company.data');
282 Company.Widget = function() { ... }
283 Company.data.CustomStore = function(config) { ... }
284 </code></pre>
285          * @param {String} namespace1
286          * @param {String} namespace2
287          * @param {String} etc
288          * @method namespace
289          */
290         namespace : function(){
291             var a=arguments, o=null, i, j, d, rt;
292             for (i=0; i<a.length; ++i) {
293                 d=a[i].split(".");
294                 rt = d[0];
295                 /** eval:var:o */
296                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
297                 for (j=1; j<d.length; ++j) {
298                     o[d[j]]=o[d[j]] || {};
299                     o=o[d[j]];
300                 }
301             }
302         },
303         /**
304          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
305          * <pre><code>
306 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
307 Roo.factory(conf, Roo.data);
308 </code></pre>
309          * @param {String} classname
310          * @param {String} namespace (optional)
311          * @method factory
312          */
313          
314         factory : function(c, ns)
315         {
316             // no xtype, no ns or c.xns - or forced off by c.xns
317             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
318                 return c;
319             }
320             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
321             if (c.constructor == ns[c.xtype]) {// already created...
322                 return c;
323             }
324             if (ns[c.xtype]) {
325                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
326                 var ret = new ns[c.xtype](c);
327                 ret.xns = false;
328                 return ret;
329             }
330             c.xns = false; // prevent recursion..
331             return c;
332         },
333          /**
334          * Logs to console if it can.
335          *
336          * @param {String|Object} string
337          * @method log
338          */
339         log : function(s)
340         {
341             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
342                 return; // alerT?
343             }
344             console.log(s);
345             
346         },
347         /**
348          * 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.
349          * @param {Object} o
350          * @return {String}
351          */
352         urlEncode : function(o){
353             if(!o){
354                 return "";
355             }
356             var buf = [];
357             for(var key in o){
358                 var ov = o[key], k = Roo.encodeURIComponent(key);
359                 var type = typeof ov;
360                 if(type == 'undefined'){
361                     buf.push(k, "=&");
362                 }else if(type != "function" && type != "object"){
363                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
364                 }else if(ov instanceof Array){
365                     if (ov.length) {
366                             for(var i = 0, len = ov.length; i < len; i++) {
367                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
368                             }
369                         } else {
370                             buf.push(k, "=&");
371                         }
372                 }
373             }
374             buf.pop();
375             return buf.join("");
376         },
377          /**
378          * Safe version of encodeURIComponent
379          * @param {String} data 
380          * @return {String} 
381          */
382         
383         encodeURIComponent : function (data)
384         {
385             try {
386                 return encodeURIComponent(data);
387             } catch(e) {} // should be an uri encode error.
388             
389             if (data == '' || data == null){
390                return '';
391             }
392             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
393             function nibble_to_hex(nibble){
394                 var chars = '0123456789ABCDEF';
395                 return chars.charAt(nibble);
396             }
397             data = data.toString();
398             var buffer = '';
399             for(var i=0; i<data.length; i++){
400                 var c = data.charCodeAt(i);
401                 var bs = new Array();
402                 if (c > 0x10000){
403                         // 4 bytes
404                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
405                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
406                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
407                     bs[3] = 0x80 | (c & 0x3F);
408                 }else if (c > 0x800){
409                          // 3 bytes
410                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
411                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
412                     bs[2] = 0x80 | (c & 0x3F);
413                 }else if (c > 0x80){
414                        // 2 bytes
415                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
416                     bs[1] = 0x80 | (c & 0x3F);
417                 }else{
418                         // 1 byte
419                     bs[0] = c;
420                 }
421                 for(var j=0; j<bs.length; j++){
422                     var b = bs[j];
423                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
424                             + nibble_to_hex(b &0x0F);
425                     buffer += '%'+hex;
426                }
427             }
428             return buffer;    
429              
430         },
431
432         /**
433          * 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]}.
434          * @param {String} string
435          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
436          * @return {Object} A literal with members
437          */
438         urlDecode : function(string, overwrite){
439             if(!string || !string.length){
440                 return {};
441             }
442             var obj = {};
443             var pairs = string.split('&');
444             var pair, name, value;
445             for(var i = 0, len = pairs.length; i < len; i++){
446                 pair = pairs[i].split('=');
447                 name = decodeURIComponent(pair[0]);
448                 value = decodeURIComponent(pair[1]);
449                 if(overwrite !== true){
450                     if(typeof obj[name] == "undefined"){
451                         obj[name] = value;
452                     }else if(typeof obj[name] == "string"){
453                         obj[name] = [obj[name]];
454                         obj[name].push(value);
455                     }else{
456                         obj[name].push(value);
457                     }
458                 }else{
459                     obj[name] = value;
460                 }
461             }
462             return obj;
463         },
464
465         /**
466          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
467          * passed array is not really an array, your function is called once with it.
468          * The supplied function is called with (Object item, Number index, Array allItems).
469          * @param {Array/NodeList/Mixed} array
470          * @param {Function} fn
471          * @param {Object} scope
472          */
473         each : function(array, fn, scope){
474             if(typeof array.length == "undefined" || typeof array == "string"){
475                 array = [array];
476             }
477             for(var i = 0, len = array.length; i < len; i++){
478                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
479             }
480         },
481
482         // deprecated
483         combine : function(){
484             var as = arguments, l = as.length, r = [];
485             for(var i = 0; i < l; i++){
486                 var a = as[i];
487                 if(a instanceof Array){
488                     r = r.concat(a);
489                 }else if(a.length !== undefined && !a.substr){
490                     r = r.concat(Array.prototype.slice.call(a, 0));
491                 }else{
492                     r.push(a);
493                 }
494             }
495             return r;
496         },
497
498         /**
499          * Escapes the passed string for use in a regular expression
500          * @param {String} str
501          * @return {String}
502          */
503         escapeRe : function(s) {
504             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
505         },
506
507         // internal
508         callback : function(cb, scope, args, delay){
509             if(typeof cb == "function"){
510                 if(delay){
511                     cb.defer(delay, scope, args || []);
512                 }else{
513                     cb.apply(scope, args || []);
514                 }
515             }
516         },
517
518         /**
519          * Return the dom node for the passed string (id), dom node, or Roo.Element
520          * @param {String/HTMLElement/Roo.Element} el
521          * @return HTMLElement
522          */
523         getDom : function(el){
524             if(!el){
525                 return null;
526             }
527             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
528         },
529
530         /**
531         * Shorthand for {@link Roo.ComponentMgr#get}
532         * @param {String} id
533         * @return Roo.Component
534         */
535         getCmp : function(id){
536             return Roo.ComponentMgr.get(id);
537         },
538          
539         num : function(v, defaultValue){
540             if(typeof v != 'number'){
541                 return defaultValue;
542             }
543             return v;
544         },
545
546         destroy : function(){
547             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
548                 var as = a[i];
549                 if(as){
550                     if(as.dom){
551                         as.removeAllListeners();
552                         as.remove();
553                         continue;
554                     }
555                     if(typeof as.purgeListeners == 'function'){
556                         as.purgeListeners();
557                     }
558                     if(typeof as.destroy == 'function'){
559                         as.destroy();
560                     }
561                 }
562             }
563         },
564
565         // inpired by a similar function in mootools library
566         /**
567          * Returns the type of object that is passed in. If the object passed in is null or undefined it
568          * return false otherwise it returns one of the following values:<ul>
569          * <li><b>string</b>: If the object passed is a string</li>
570          * <li><b>number</b>: If the object passed is a number</li>
571          * <li><b>boolean</b>: If the object passed is a boolean value</li>
572          * <li><b>function</b>: If the object passed is a function reference</li>
573          * <li><b>object</b>: If the object passed is an object</li>
574          * <li><b>array</b>: If the object passed is an array</li>
575          * <li><b>regexp</b>: If the object passed is a regular expression</li>
576          * <li><b>element</b>: If the object passed is a DOM Element</li>
577          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
578          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
579          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
580          * @param {Mixed} object
581          * @return {String}
582          */
583         type : function(o){
584             if(o === undefined || o === null){
585                 return false;
586             }
587             if(o.htmlElement){
588                 return 'element';
589             }
590             var t = typeof o;
591             if(t == 'object' && o.nodeName) {
592                 switch(o.nodeType) {
593                     case 1: return 'element';
594                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
595                 }
596             }
597             if(t == 'object' || t == 'function') {
598                 switch(o.constructor) {
599                     case Array: return 'array';
600                     case RegExp: return 'regexp';
601                 }
602                 if(typeof o.length == 'number' && typeof o.item == 'function') {
603                     return 'nodelist';
604                 }
605             }
606             return t;
607         },
608
609         /**
610          * Returns true if the passed value is null, undefined or an empty string (optional).
611          * @param {Mixed} value The value to test
612          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
613          * @return {Boolean}
614          */
615         isEmpty : function(v, allowBlank){
616             return v === null || v === undefined || (!allowBlank ? v === '' : false);
617         },
618         
619         /** @type Boolean */
620         isOpera : isOpera,
621         /** @type Boolean */
622         isSafari : isSafari,
623         /** @type Boolean */
624         isFirefox : isFirefox,
625         /** @type Boolean */
626         isIE : isIE,
627         /** @type Boolean */
628         isIE7 : isIE7,
629         /** @type Boolean */
630         isIE11 : isIE11,
631         /** @type Boolean */
632         isGecko : isGecko,
633         /** @type Boolean */
634         isBorderBox : isBorderBox,
635         /** @type Boolean */
636         isWindows : isWindows,
637         /** @type Boolean */
638         isLinux : isLinux,
639         /** @type Boolean */
640         isMac : isMac,
641         /** @type Boolean */
642         isIOS : isIOS,
643         /** @type Boolean */
644         isAndroid : isAndroid,
645         /** @type Boolean */
646         isTouch : isTouch,
647
648         /**
649          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
650          * you may want to set this to true.
651          * @type Boolean
652          */
653         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
654         
655         
656                 
657         /**
658          * Selects a single element as a Roo Element
659          * This is about as close as you can get to jQuery's $('do crazy stuff')
660          * @param {String} selector The selector/xpath query
661          * @param {Node} root (optional) The start of the query (defaults to document).
662          * @return {Roo.Element}
663          */
664         selectNode : function(selector, root) 
665         {
666             var node = Roo.DomQuery.selectNode(selector,root);
667             return node ? Roo.get(node) : new Roo.Element(false);
668         }
669         
670     });
671
672
673 })();
674
675 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
676                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
677                 "Roo.app", "Roo.ux",
678                 "Roo.bootstrap",
679                 "Roo.bootstrap.dash");
680 /*
681  * Based on:
682  * Ext JS Library 1.1.1
683  * Copyright(c) 2006-2007, Ext JS, LLC.
684  *
685  * Originally Released Under LGPL - original licence link has changed is not relivant.
686  *
687  * Fork - LGPL
688  * <script type="text/javascript">
689  */
690
691 (function() {    
692     // wrappedn so fnCleanup is not in global scope...
693     if(Roo.isIE) {
694         function fnCleanUp() {
695             var p = Function.prototype;
696             delete p.createSequence;
697             delete p.defer;
698             delete p.createDelegate;
699             delete p.createCallback;
700             delete p.createInterceptor;
701
702             window.detachEvent("onunload", fnCleanUp);
703         }
704         window.attachEvent("onunload", fnCleanUp);
705     }
706 })();
707
708
709 /**
710  * @class Function
711  * These functions are available on every Function object (any JavaScript function).
712  */
713 Roo.apply(Function.prototype, {
714      /**
715      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
716      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
717      * Will create a function that is bound to those 2 args.
718      * @return {Function} The new function
719     */
720     createCallback : function(/*args...*/){
721         // make args available, in function below
722         var args = arguments;
723         var method = this;
724         return function() {
725             return method.apply(window, args);
726         };
727     },
728
729     /**
730      * Creates a delegate (callback) that sets the scope to obj.
731      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
732      * Will create a function that is automatically scoped to this.
733      * @param {Object} obj (optional) The object for which the scope is set
734      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
735      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
736      *                                             if a number the args are inserted at the specified position
737      * @return {Function} The new function
738      */
739     createDelegate : function(obj, args, appendArgs){
740         var method = this;
741         return function() {
742             var callArgs = args || arguments;
743             if(appendArgs === true){
744                 callArgs = Array.prototype.slice.call(arguments, 0);
745                 callArgs = callArgs.concat(args);
746             }else if(typeof appendArgs == "number"){
747                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
748                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
749                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
750             }
751             return method.apply(obj || window, callArgs);
752         };
753     },
754
755     /**
756      * Calls this function after the number of millseconds specified.
757      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Number} The timeout id that can be used with clearTimeout
763      */
764     defer : function(millis, obj, args, appendArgs){
765         var fn = this.createDelegate(obj, args, appendArgs);
766         if(millis){
767             return setTimeout(fn, millis);
768         }
769         fn();
770         return 0;
771     },
772     /**
773      * Create a combined function call sequence of the original function + the passed function.
774      * The resulting function returns the results of the original function.
775      * The passed fcn is called with the parameters of the original function
776      * @param {Function} fcn The function to sequence
777      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
778      * @return {Function} The new function
779      */
780     createSequence : function(fcn, scope){
781         if(typeof fcn != "function"){
782             return this;
783         }
784         var method = this;
785         return function() {
786             var retval = method.apply(this || window, arguments);
787             fcn.apply(scope || this || window, arguments);
788             return retval;
789         };
790     },
791
792     /**
793      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
794      * The resulting function returns the results of the original function.
795      * The passed fcn is called with the parameters of the original function.
796      * @addon
797      * @param {Function} fcn The function to call before the original
798      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
799      * @return {Function} The new function
800      */
801     createInterceptor : function(fcn, scope){
802         if(typeof fcn != "function"){
803             return this;
804         }
805         var method = this;
806         return function() {
807             fcn.target = this;
808             fcn.method = method;
809             if(fcn.apply(scope || this || window, arguments) === false){
810                 return;
811             }
812             return method.apply(this || window, arguments);
813         };
814     }
815 });
816 /*
817  * Based on:
818  * Ext JS Library 1.1.1
819  * Copyright(c) 2006-2007, Ext JS, LLC.
820  *
821  * Originally Released Under LGPL - original licence link has changed is not relivant.
822  *
823  * Fork - LGPL
824  * <script type="text/javascript">
825  */
826
827 Roo.applyIf(String, {
828     
829     /** @scope String */
830     
831     /**
832      * Escapes the passed string for ' and \
833      * @param {String} string The string to escape
834      * @return {String} The escaped string
835      * @static
836      */
837     escape : function(string) {
838         return string.replace(/('|\\)/g, "\\$1");
839     },
840
841     /**
842      * Pads the left side of a string with a specified character.  This is especially useful
843      * for normalizing number and date strings.  Example usage:
844      * <pre><code>
845 var s = String.leftPad('123', 5, '0');
846 // s now contains the string: '00123'
847 </code></pre>
848      * @param {String} string The original string
849      * @param {Number} size The total length of the output string
850      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
851      * @return {String} The padded string
852      * @static
853      */
854     leftPad : function (val, size, ch) {
855         var result = new String(val);
856         if(ch === null || ch === undefined || ch === '') {
857             ch = " ";
858         }
859         while (result.length < size) {
860             result = ch + result;
861         }
862         return result;
863     },
864
865     /**
866      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
867      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
868      * <pre><code>
869 var cls = 'my-class', text = 'Some text';
870 var s = String.format('<div class="{0}">{1}</div>', cls, text);
871 // s now contains the string: '<div class="my-class">Some text</div>'
872 </code></pre>
873      * @param {String} string The tokenized string to be formatted
874      * @param {String} value1 The value to replace token {0}
875      * @param {String} value2 Etc...
876      * @return {String} The formatted string
877      * @static
878      */
879     format : function(format){
880         var args = Array.prototype.slice.call(arguments, 1);
881         return format.replace(/\{(\d+)\}/g, function(m, i){
882             return Roo.util.Format.htmlEncode(args[i]);
883         });
884     }
885 });
886
887 /**
888  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
889  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
890  * they are already different, the first value passed in is returned.  Note that this method returns the new value
891  * but does not change the current string.
892  * <pre><code>
893 // alternate sort directions
894 sort = sort.toggle('ASC', 'DESC');
895
896 // instead of conditional logic:
897 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
898 </code></pre>
899  * @param {String} value The value to compare to the current string
900  * @param {String} other The new value to use if the string already equals the first value passed in
901  * @return {String} The new value
902  */
903  
904 String.prototype.toggle = function(value, other){
905     return this == value ? other : value;
906 };/*
907  * Based on:
908  * Ext JS Library 1.1.1
909  * Copyright(c) 2006-2007, Ext JS, LLC.
910  *
911  * Originally Released Under LGPL - original licence link has changed is not relivant.
912  *
913  * Fork - LGPL
914  * <script type="text/javascript">
915  */
916
917  /**
918  * @class Number
919  */
920 Roo.applyIf(Number.prototype, {
921     /**
922      * Checks whether or not the current number is within a desired range.  If the number is already within the
923      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
924      * exceeded.  Note that this method returns the constrained value but does not change the current number.
925      * @param {Number} min The minimum number in the range
926      * @param {Number} max The maximum number in the range
927      * @return {Number} The constrained value if outside the range, otherwise the current value
928      */
929     constrain : function(min, max){
930         return Math.min(Math.max(this, min), max);
931     }
932 });/*
933  * Based on:
934  * Ext JS Library 1.1.1
935  * Copyright(c) 2006-2007, Ext JS, LLC.
936  *
937  * Originally Released Under LGPL - original licence link has changed is not relivant.
938  *
939  * Fork - LGPL
940  * <script type="text/javascript">
941  */
942  /**
943  * @class Array
944  */
945 Roo.applyIf(Array.prototype, {
946     /**
947      * 
948      * Checks whether or not the specified object exists in the array.
949      * @param {Object} o The object to check for
950      * @return {Number} The index of o in the array (or -1 if it is not found)
951      */
952     indexOf : function(o){
953        for (var i = 0, len = this.length; i < len; i++){
954               if(this[i] == o) { return i; }
955        }
956            return -1;
957     },
958
959     /**
960      * Removes the specified object from the array.  If the object is not found nothing happens.
961      * @param {Object} o The object to remove
962      */
963     remove : function(o){
964        var index = this.indexOf(o);
965        if(index != -1){
966            this.splice(index, 1);
967        }
968     },
969     /**
970      * Map (JS 1.6 compatibility)
971      * @param {Function} function  to call
972      */
973     map : function(fun )
974     {
975         var len = this.length >>> 0;
976         if (typeof fun != "function") {
977             throw new TypeError();
978         }
979         var res = new Array(len);
980         var thisp = arguments[1];
981         for (var i = 0; i < len; i++)
982         {
983             if (i in this) {
984                 res[i] = fun.call(thisp, this[i], i, this);
985             }
986         }
987
988         return res;
989     }
990     
991 });
992
993
994  
995 /*
996  * Based on:
997  * Ext JS Library 1.1.1
998  * Copyright(c) 2006-2007, Ext JS, LLC.
999  *
1000  * Originally Released Under LGPL - original licence link has changed is not relivant.
1001  *
1002  * Fork - LGPL
1003  * <script type="text/javascript">
1004  */
1005
1006 /**
1007  * @class Date
1008  *
1009  * The date parsing and format syntax is a subset of
1010  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1011  * supported will provide results equivalent to their PHP versions.
1012  *
1013  * Following is the list of all currently supported formats:
1014  *<pre>
1015 Sample date:
1016 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1017
1018 Format  Output      Description
1019 ------  ----------  --------------------------------------------------------------
1020   d      10         Day of the month, 2 digits with leading zeros
1021   D      Wed        A textual representation of a day, three letters
1022   j      10         Day of the month without leading zeros
1023   l      Wednesday  A full textual representation of the day of the week
1024   S      th         English ordinal day of month suffix, 2 chars (use with j)
1025   w      3          Numeric representation of the day of the week
1026   z      9          The julian date, or day of the year (0-365)
1027   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1028   F      January    A full textual representation of the month
1029   m      01         Numeric representation of a month, with leading zeros
1030   M      Jan        Month name abbreviation, three letters
1031   n      1          Numeric representation of a month, without leading zeros
1032   t      31         Number of days in the given month
1033   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1034   Y      2007       A full numeric representation of a year, 4 digits
1035   y      07         A two digit representation of a year
1036   a      pm         Lowercase Ante meridiem and Post meridiem
1037   A      PM         Uppercase Ante meridiem and Post meridiem
1038   g      3          12-hour format of an hour without leading zeros
1039   G      15         24-hour format of an hour without leading zeros
1040   h      03         12-hour format of an hour with leading zeros
1041   H      15         24-hour format of an hour with leading zeros
1042   i      05         Minutes with leading zeros
1043   s      01         Seconds, with leading zeros
1044   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1045   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1046   T      CST        Timezone setting of the machine running the code
1047   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1048 </pre>
1049  *
1050  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1051  * <pre><code>
1052 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1053 document.write(dt.format('Y-m-d'));                         //2007-01-10
1054 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1055 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
1056  </code></pre>
1057  *
1058  * Here are some standard date/time patterns that you might find helpful.  They
1059  * are not part of the source of Date.js, but to use them you can simply copy this
1060  * block of code into any script that is included after Date.js and they will also become
1061  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1062  * <pre><code>
1063 Date.patterns = {
1064     ISO8601Long:"Y-m-d H:i:s",
1065     ISO8601Short:"Y-m-d",
1066     ShortDate: "n/j/Y",
1067     LongDate: "l, F d, Y",
1068     FullDateTime: "l, F d, Y g:i:s A",
1069     MonthDay: "F d",
1070     ShortTime: "g:i A",
1071     LongTime: "g:i:s A",
1072     SortableDateTime: "Y-m-d\\TH:i:s",
1073     UniversalSortableDateTime: "Y-m-d H:i:sO",
1074     YearMonth: "F, Y"
1075 };
1076 </code></pre>
1077  *
1078  * Example usage:
1079  * <pre><code>
1080 var dt = new Date();
1081 document.write(dt.format(Date.patterns.ShortDate));
1082  </code></pre>
1083  */
1084
1085 /*
1086  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1087  * They generate precompiled functions from date formats instead of parsing and
1088  * processing the pattern every time you format a date.  These functions are available
1089  * on every Date object (any javascript function).
1090  *
1091  * The original article and download are here:
1092  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1093  *
1094  */
1095  
1096  
1097  // was in core
1098 /**
1099  Returns the number of milliseconds between this date and date
1100  @param {Date} date (optional) Defaults to now
1101  @return {Number} The diff in milliseconds
1102  @member Date getElapsed
1103  */
1104 Date.prototype.getElapsed = function(date) {
1105         return Math.abs((date || new Date()).getTime()-this.getTime());
1106 };
1107 // was in date file..
1108
1109
1110 // private
1111 Date.parseFunctions = {count:0};
1112 // private
1113 Date.parseRegexes = [];
1114 // private
1115 Date.formatFunctions = {count:0};
1116
1117 // private
1118 Date.prototype.dateFormat = function(format) {
1119     if (Date.formatFunctions[format] == null) {
1120         Date.createNewFormat(format);
1121     }
1122     var func = Date.formatFunctions[format];
1123     return this[func]();
1124 };
1125
1126
1127 /**
1128  * Formats a date given the supplied format string
1129  * @param {String} format The format string
1130  * @return {String} The formatted date
1131  * @method
1132  */
1133 Date.prototype.format = Date.prototype.dateFormat;
1134
1135 // private
1136 Date.createNewFormat = function(format) {
1137     var funcName = "format" + Date.formatFunctions.count++;
1138     Date.formatFunctions[format] = funcName;
1139     var code = "Date.prototype." + funcName + " = function(){return ";
1140     var special = false;
1141     var ch = '';
1142     for (var i = 0; i < format.length; ++i) {
1143         ch = format.charAt(i);
1144         if (!special && ch == "\\") {
1145             special = true;
1146         }
1147         else if (special) {
1148             special = false;
1149             code += "'" + String.escape(ch) + "' + ";
1150         }
1151         else {
1152             code += Date.getFormatCode(ch);
1153         }
1154     }
1155     /** eval:var:zzzzzzzzzzzzz */
1156     eval(code.substring(0, code.length - 3) + ";}");
1157 };
1158
1159 // private
1160 Date.getFormatCode = function(character) {
1161     switch (character) {
1162     case "d":
1163         return "String.leftPad(this.getDate(), 2, '0') + ";
1164     case "D":
1165         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1166     case "j":
1167         return "this.getDate() + ";
1168     case "l":
1169         return "Date.dayNames[this.getDay()] + ";
1170     case "S":
1171         return "this.getSuffix() + ";
1172     case "w":
1173         return "this.getDay() + ";
1174     case "z":
1175         return "this.getDayOfYear() + ";
1176     case "W":
1177         return "this.getWeekOfYear() + ";
1178     case "F":
1179         return "Date.monthNames[this.getMonth()] + ";
1180     case "m":
1181         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1182     case "M":
1183         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1184     case "n":
1185         return "(this.getMonth() + 1) + ";
1186     case "t":
1187         return "this.getDaysInMonth() + ";
1188     case "L":
1189         return "(this.isLeapYear() ? 1 : 0) + ";
1190     case "Y":
1191         return "this.getFullYear() + ";
1192     case "y":
1193         return "('' + this.getFullYear()).substring(2, 4) + ";
1194     case "a":
1195         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1196     case "A":
1197         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1198     case "g":
1199         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1200     case "G":
1201         return "this.getHours() + ";
1202     case "h":
1203         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1204     case "H":
1205         return "String.leftPad(this.getHours(), 2, '0') + ";
1206     case "i":
1207         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1208     case "s":
1209         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1210     case "O":
1211         return "this.getGMTOffset() + ";
1212     case "P":
1213         return "this.getGMTColonOffset() + ";
1214     case "T":
1215         return "this.getTimezone() + ";
1216     case "Z":
1217         return "(this.getTimezoneOffset() * -60) + ";
1218     default:
1219         return "'" + String.escape(character) + "' + ";
1220     }
1221 };
1222
1223 /**
1224  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1225  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1226  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1227  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1228  * string or the parse operation will fail.
1229  * Example Usage:
1230 <pre><code>
1231 //dt = Fri May 25 2007 (current date)
1232 var dt = new Date();
1233
1234 //dt = Thu May 25 2006 (today's month/day in 2006)
1235 dt = Date.parseDate("2006", "Y");
1236
1237 //dt = Sun Jan 15 2006 (all date parts specified)
1238 dt = Date.parseDate("2006-1-15", "Y-m-d");
1239
1240 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1241 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1242 </code></pre>
1243  * @param {String} input The unparsed date as a string
1244  * @param {String} format The format the date is in
1245  * @return {Date} The parsed date
1246  * @static
1247  */
1248 Date.parseDate = function(input, format) {
1249     if (Date.parseFunctions[format] == null) {
1250         Date.createParser(format);
1251     }
1252     var func = Date.parseFunctions[format];
1253     return Date[func](input);
1254 };
1255 /**
1256  * @private
1257  */
1258
1259 Date.createParser = function(format) {
1260     var funcName = "parse" + Date.parseFunctions.count++;
1261     var regexNum = Date.parseRegexes.length;
1262     var currentGroup = 1;
1263     Date.parseFunctions[format] = funcName;
1264
1265     var code = "Date." + funcName + " = function(input){\n"
1266         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1267         + "var d = new Date();\n"
1268         + "y = d.getFullYear();\n"
1269         + "m = d.getMonth();\n"
1270         + "d = d.getDate();\n"
1271         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1272         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1273         + "if (results && results.length > 0) {";
1274     var regex = "";
1275
1276     var special = false;
1277     var ch = '';
1278     for (var i = 0; i < format.length; ++i) {
1279         ch = format.charAt(i);
1280         if (!special && ch == "\\") {
1281             special = true;
1282         }
1283         else if (special) {
1284             special = false;
1285             regex += String.escape(ch);
1286         }
1287         else {
1288             var obj = Date.formatCodeToRegex(ch, currentGroup);
1289             currentGroup += obj.g;
1290             regex += obj.s;
1291             if (obj.g && obj.c) {
1292                 code += obj.c;
1293             }
1294         }
1295     }
1296
1297     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1298         + "{v = new Date(y, m, d, h, i, s);}\n"
1299         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1300         + "{v = new Date(y, m, d, h, i);}\n"
1301         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1302         + "{v = new Date(y, m, d, h);}\n"
1303         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1304         + "{v = new Date(y, m, d);}\n"
1305         + "else if (y >= 0 && m >= 0)\n"
1306         + "{v = new Date(y, m);}\n"
1307         + "else if (y >= 0)\n"
1308         + "{v = new Date(y);}\n"
1309         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1310         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1311         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1312         + ";}";
1313
1314     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1315     /** eval:var:zzzzzzzzzzzzz */
1316     eval(code);
1317 };
1318
1319 // private
1320 Date.formatCodeToRegex = function(character, currentGroup) {
1321     switch (character) {
1322     case "D":
1323         return {g:0,
1324         c:null,
1325         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1326     case "j":
1327         return {g:1,
1328             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1329             s:"(\\d{1,2})"}; // day of month without leading zeroes
1330     case "d":
1331         return {g:1,
1332             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1333             s:"(\\d{2})"}; // day of month with leading zeroes
1334     case "l":
1335         return {g:0,
1336             c:null,
1337             s:"(?:" + Date.dayNames.join("|") + ")"};
1338     case "S":
1339         return {g:0,
1340             c:null,
1341             s:"(?:st|nd|rd|th)"};
1342     case "w":
1343         return {g:0,
1344             c:null,
1345             s:"\\d"};
1346     case "z":
1347         return {g:0,
1348             c:null,
1349             s:"(?:\\d{1,3})"};
1350     case "W":
1351         return {g:0,
1352             c:null,
1353             s:"(?:\\d{2})"};
1354     case "F":
1355         return {g:1,
1356             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1357             s:"(" + Date.monthNames.join("|") + ")"};
1358     case "M":
1359         return {g:1,
1360             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1361             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1362     case "n":
1363         return {g:1,
1364             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1365             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1366     case "m":
1367         return {g:1,
1368             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1369             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1370     case "t":
1371         return {g:0,
1372             c:null,
1373             s:"\\d{1,2}"};
1374     case "L":
1375         return {g:0,
1376             c:null,
1377             s:"(?:1|0)"};
1378     case "Y":
1379         return {g:1,
1380             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{4})"};
1382     case "y":
1383         return {g:1,
1384             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1385                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386             s:"(\\d{1,2})"};
1387     case "a":
1388         return {g:1,
1389             c:"if (results[" + currentGroup + "] == 'am') {\n"
1390                 + "if (h == 12) { h = 0; }\n"
1391                 + "} else { if (h < 12) { h += 12; }}",
1392             s:"(am|pm)"};
1393     case "A":
1394         return {g:1,
1395             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1396                 + "if (h == 12) { h = 0; }\n"
1397                 + "} else { if (h < 12) { h += 12; }}",
1398             s:"(AM|PM)"};
1399     case "g":
1400     case "G":
1401         return {g:1,
1402             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1403             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1404     case "h":
1405     case "H":
1406         return {g:1,
1407             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1408             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1409     case "i":
1410         return {g:1,
1411             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412             s:"(\\d{2})"};
1413     case "s":
1414         return {g:1,
1415             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1416             s:"(\\d{2})"};
1417     case "O":
1418         return {g:1,
1419             c:[
1420                 "o = results[", currentGroup, "];\n",
1421                 "var sn = o.substring(0,1);\n", // get + / - sign
1422                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1423                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1424                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1425                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1426             ].join(""),
1427             s:"([+\-]\\d{2,4})"};
1428     
1429     
1430     case "P":
1431         return {g:1,
1432                 c:[
1433                    "o = results[", currentGroup, "];\n",
1434                    "var sn = o.substring(0,1);\n",
1435                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1436                    "var mn = o.substring(4,6) % 60;\n",
1437                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1438                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1439             ].join(""),
1440             s:"([+\-]\\d{4})"};
1441     case "T":
1442         return {g:0,
1443             c:null,
1444             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1445     case "Z":
1446         return {g:1,
1447             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1448                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1449             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450     default:
1451         return {g:0,
1452             c:null,
1453             s:String.escape(character)};
1454     }
1455 };
1456
1457 /**
1458  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1459  * @return {String} The abbreviated timezone name (e.g. 'CST')
1460  */
1461 Date.prototype.getTimezone = function() {
1462     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 };
1464
1465 /**
1466  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1467  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1468  */
1469 Date.prototype.getGMTOffset = function() {
1470     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1471         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 };
1474
1475 /**
1476  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1477  * @return {String} 2-characters representing hours and 2-characters representing minutes
1478  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1479  */
1480 Date.prototype.getGMTColonOffset = function() {
1481         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1482                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1483                 + ":"
1484                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 }
1486
1487 /**
1488  * Get the numeric day number of the year, adjusted for leap year.
1489  * @return {Number} 0 through 364 (365 in leap years)
1490  */
1491 Date.prototype.getDayOfYear = function() {
1492     var num = 0;
1493     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1494     for (var i = 0; i < this.getMonth(); ++i) {
1495         num += Date.daysInMonth[i];
1496     }
1497     return num + this.getDate() - 1;
1498 };
1499
1500 /**
1501  * Get the string representation of the numeric week number of the year
1502  * (equivalent to the format specifier 'W').
1503  * @return {String} '00' through '52'
1504  */
1505 Date.prototype.getWeekOfYear = function() {
1506     // Skip to Thursday of this week
1507     var now = this.getDayOfYear() + (4 - this.getDay());
1508     // Find the first Thursday of the year
1509     var jan1 = new Date(this.getFullYear(), 0, 1);
1510     var then = (7 - jan1.getDay() + 4);
1511     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 };
1513
1514 /**
1515  * Whether or not the current date is in a leap year.
1516  * @return {Boolean} True if the current date is in a leap year, else false
1517  */
1518 Date.prototype.isLeapYear = function() {
1519     var year = this.getFullYear();
1520     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 };
1522
1523 /**
1524  * Get the first day of the current month, adjusted for leap year.  The returned value
1525  * is the numeric day index within the week (0-6) which can be used in conjunction with
1526  * the {@link #monthNames} array to retrieve the textual day name.
1527  * Example:
1528  *<pre><code>
1529 var dt = new Date('1/10/2007');
1530 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1531 </code></pre>
1532  * @return {Number} The day number (0-6)
1533  */
1534 Date.prototype.getFirstDayOfMonth = function() {
1535     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1536     return (day < 0) ? (day + 7) : day;
1537 };
1538
1539 /**
1540  * Get the last day of the current month, adjusted for leap year.  The returned value
1541  * is the numeric day index within the week (0-6) which can be used in conjunction with
1542  * the {@link #monthNames} array to retrieve the textual day name.
1543  * Example:
1544  *<pre><code>
1545 var dt = new Date('1/10/2007');
1546 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1547 </code></pre>
1548  * @return {Number} The day number (0-6)
1549  */
1550 Date.prototype.getLastDayOfMonth = function() {
1551     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1552     return (day < 0) ? (day + 7) : day;
1553 };
1554
1555
1556 /**
1557  * Get the first date of this date's month
1558  * @return {Date}
1559  */
1560 Date.prototype.getFirstDateOfMonth = function() {
1561     return new Date(this.getFullYear(), this.getMonth(), 1);
1562 };
1563
1564 /**
1565  * Get the last date of this date's month
1566  * @return {Date}
1567  */
1568 Date.prototype.getLastDateOfMonth = function() {
1569     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1570 };
1571 /**
1572  * Get the number of days in the current month, adjusted for leap year.
1573  * @return {Number} The number of days in the month
1574  */
1575 Date.prototype.getDaysInMonth = function() {
1576     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577     return Date.daysInMonth[this.getMonth()];
1578 };
1579
1580 /**
1581  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1582  * @return {String} 'st, 'nd', 'rd' or 'th'
1583  */
1584 Date.prototype.getSuffix = function() {
1585     switch (this.getDate()) {
1586         case 1:
1587         case 21:
1588         case 31:
1589             return "st";
1590         case 2:
1591         case 22:
1592             return "nd";
1593         case 3:
1594         case 23:
1595             return "rd";
1596         default:
1597             return "th";
1598     }
1599 };
1600
1601 // private
1602 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1603
1604 /**
1605  * An array of textual month names.
1606  * Override these values for international dates, for example...
1607  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1608  * @type Array
1609  * @static
1610  */
1611 Date.monthNames =
1612    ["January",
1613     "February",
1614     "March",
1615     "April",
1616     "May",
1617     "June",
1618     "July",
1619     "August",
1620     "September",
1621     "October",
1622     "November",
1623     "December"];
1624
1625 /**
1626  * An array of textual day names.
1627  * Override these values for international dates, for example...
1628  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629  * @type Array
1630  * @static
1631  */
1632 Date.dayNames =
1633    ["Sunday",
1634     "Monday",
1635     "Tuesday",
1636     "Wednesday",
1637     "Thursday",
1638     "Friday",
1639     "Saturday"];
1640
1641 // private
1642 Date.y2kYear = 50;
1643 // private
1644 Date.monthNumbers = {
1645     Jan:0,
1646     Feb:1,
1647     Mar:2,
1648     Apr:3,
1649     May:4,
1650     Jun:5,
1651     Jul:6,
1652     Aug:7,
1653     Sep:8,
1654     Oct:9,
1655     Nov:10,
1656     Dec:11};
1657
1658 /**
1659  * Creates and returns a new Date instance with the exact same date value as the called instance.
1660  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1661  * variable will also be changed.  When the intention is to create a new variable that will not
1662  * modify the original instance, you should create a clone.
1663  *
1664  * Example of correctly cloning a date:
1665  * <pre><code>
1666 //wrong way:
1667 var orig = new Date('10/1/2006');
1668 var copy = orig;
1669 copy.setDate(5);
1670 document.write(orig);  //returns 'Thu Oct 05 2006'!
1671
1672 //correct way:
1673 var orig = new Date('10/1/2006');
1674 var copy = orig.clone();
1675 copy.setDate(5);
1676 document.write(orig);  //returns 'Thu Oct 01 2006'
1677 </code></pre>
1678  * @return {Date} The new Date instance
1679  */
1680 Date.prototype.clone = function() {
1681         return new Date(this.getTime());
1682 };
1683
1684 /**
1685  * Clears any time information from this date
1686  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1687  @return {Date} this or the clone
1688  */
1689 Date.prototype.clearTime = function(clone){
1690     if(clone){
1691         return this.clone().clearTime();
1692     }
1693     this.setHours(0);
1694     this.setMinutes(0);
1695     this.setSeconds(0);
1696     this.setMilliseconds(0);
1697     return this;
1698 };
1699
1700 // private
1701 // safari setMonth is broken -- check that this is only donw once...
1702 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1703     Date.brokenSetMonth = Date.prototype.setMonth;
1704         Date.prototype.setMonth = function(num){
1705                 if(num <= -1){
1706                         var n = Math.ceil(-num);
1707                         var back_year = Math.ceil(n/12);
1708                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1709                         this.setFullYear(this.getFullYear() - back_year);
1710                         return Date.brokenSetMonth.call(this, month);
1711                 } else {
1712                         return Date.brokenSetMonth.apply(this, arguments);
1713                 }
1714         };
1715 }
1716
1717 /** Date interval constant 
1718 * @static 
1719 * @type String */
1720 Date.MILLI = "ms";
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.SECOND = "s";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.MINUTE = "mi";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.HOUR = "h";
1733 /** Date interval constant 
1734 * @static 
1735 * @type String */
1736 Date.DAY = "d";
1737 /** Date interval constant 
1738 * @static 
1739 * @type String */
1740 Date.MONTH = "mo";
1741 /** Date interval constant 
1742 * @static 
1743 * @type String */
1744 Date.YEAR = "y";
1745
1746 /**
1747  * Provides a convenient method of performing basic date arithmetic.  This method
1748  * does not modify the Date instance being called - it creates and returns
1749  * a new Date instance containing the resulting date value.
1750  *
1751  * Examples:
1752  * <pre><code>
1753 //Basic usage:
1754 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1755 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1756
1757 //Negative values will subtract correctly:
1758 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1759 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1760
1761 //You can even chain several calls together in one line!
1762 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1763 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1764  </code></pre>
1765  *
1766  * @param {String} interval   A valid date interval enum value
1767  * @param {Number} value      The amount to add to the current date
1768  * @return {Date} The new Date instance
1769  */
1770 Date.prototype.add = function(interval, value){
1771   var d = this.clone();
1772   if (!interval || value === 0) { return d; }
1773   switch(interval.toLowerCase()){
1774     case Date.MILLI:
1775       d.setMilliseconds(this.getMilliseconds() + value);
1776       break;
1777     case Date.SECOND:
1778       d.setSeconds(this.getSeconds() + value);
1779       break;
1780     case Date.MINUTE:
1781       d.setMinutes(this.getMinutes() + value);
1782       break;
1783     case Date.HOUR:
1784       d.setHours(this.getHours() + value);
1785       break;
1786     case Date.DAY:
1787       d.setDate(this.getDate() + value);
1788       break;
1789     case Date.MONTH:
1790       var day = this.getDate();
1791       if(day > 28){
1792           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1793       }
1794       d.setDate(day);
1795       d.setMonth(this.getMonth() + value);
1796       break;
1797     case Date.YEAR:
1798       d.setFullYear(this.getFullYear() + value);
1799       break;
1800   }
1801   return d;
1802 };
1803 /*
1804  * Based on:
1805  * Ext JS Library 1.1.1
1806  * Copyright(c) 2006-2007, Ext JS, LLC.
1807  *
1808  * Originally Released Under LGPL - original licence link has changed is not relivant.
1809  *
1810  * Fork - LGPL
1811  * <script type="text/javascript">
1812  */
1813
1814 /**
1815  * @class Roo.lib.Dom
1816  * @static
1817  * 
1818  * Dom utils (from YIU afaik)
1819  * 
1820  **/
1821 Roo.lib.Dom = {
1822     /**
1823      * Get the view width
1824      * @param {Boolean} full True will get the full document, otherwise it's the view width
1825      * @return {Number} The width
1826      */
1827      
1828     getViewWidth : function(full) {
1829         return full ? this.getDocumentWidth() : this.getViewportWidth();
1830     },
1831     /**
1832      * Get the view height
1833      * @param {Boolean} full True will get the full document, otherwise it's the view height
1834      * @return {Number} The height
1835      */
1836     getViewHeight : function(full) {
1837         return full ? this.getDocumentHeight() : this.getViewportHeight();
1838     },
1839
1840     getDocumentHeight: function() {
1841         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1842         return Math.max(scrollHeight, this.getViewportHeight());
1843     },
1844
1845     getDocumentWidth: function() {
1846         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1847         return Math.max(scrollWidth, this.getViewportWidth());
1848     },
1849
1850     getViewportHeight: function() {
1851         var height = self.innerHeight;
1852         var mode = document.compatMode;
1853
1854         if ((mode || Roo.isIE) && !Roo.isOpera) {
1855             height = (mode == "CSS1Compat") ?
1856                      document.documentElement.clientHeight :
1857                      document.body.clientHeight;
1858         }
1859
1860         return height;
1861     },
1862
1863     getViewportWidth: function() {
1864         var width = self.innerWidth;
1865         var mode = document.compatMode;
1866
1867         if (mode || Roo.isIE) {
1868             width = (mode == "CSS1Compat") ?
1869                     document.documentElement.clientWidth :
1870                     document.body.clientWidth;
1871         }
1872         return width;
1873     },
1874
1875     isAncestor : function(p, c) {
1876         p = Roo.getDom(p);
1877         c = Roo.getDom(c);
1878         if (!p || !c) {
1879             return false;
1880         }
1881
1882         if (p.contains && !Roo.isSafari) {
1883             return p.contains(c);
1884         } else if (p.compareDocumentPosition) {
1885             return !!(p.compareDocumentPosition(c) & 16);
1886         } else {
1887             var parent = c.parentNode;
1888             while (parent) {
1889                 if (parent == p) {
1890                     return true;
1891                 }
1892                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1893                     return false;
1894                 }
1895                 parent = parent.parentNode;
1896             }
1897             return false;
1898         }
1899     },
1900
1901     getRegion : function(el) {
1902         return Roo.lib.Region.getRegion(el);
1903     },
1904
1905     getY : function(el) {
1906         return this.getXY(el)[1];
1907     },
1908
1909     getX : function(el) {
1910         return this.getXY(el)[0];
1911     },
1912
1913     getXY : function(el) {
1914         var p, pe, b, scroll, bd = document.body;
1915         el = Roo.getDom(el);
1916         var fly = Roo.lib.AnimBase.fly;
1917         if (el.getBoundingClientRect) {
1918             b = el.getBoundingClientRect();
1919             scroll = fly(document).getScroll();
1920             return [b.left + scroll.left, b.top + scroll.top];
1921         }
1922         var x = 0, y = 0;
1923
1924         p = el;
1925
1926         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1927
1928         while (p) {
1929
1930             x += p.offsetLeft;
1931             y += p.offsetTop;
1932
1933             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1934                 hasAbsolute = true;
1935             }
1936
1937             if (Roo.isGecko) {
1938                 pe = fly(p);
1939
1940                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1941                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1942
1943
1944                 x += bl;
1945                 y += bt;
1946
1947
1948                 if (p != el && pe.getStyle('overflow') != 'visible') {
1949                     x += bl;
1950                     y += bt;
1951                 }
1952             }
1953             p = p.offsetParent;
1954         }
1955
1956         if (Roo.isSafari && hasAbsolute) {
1957             x -= bd.offsetLeft;
1958             y -= bd.offsetTop;
1959         }
1960
1961         if (Roo.isGecko && !hasAbsolute) {
1962             var dbd = fly(bd);
1963             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1964             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965         }
1966
1967         p = el.parentNode;
1968         while (p && p != bd) {
1969             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1970                 x -= p.scrollLeft;
1971                 y -= p.scrollTop;
1972             }
1973             p = p.parentNode;
1974         }
1975         return [x, y];
1976     },
1977  
1978   
1979
1980
1981     setXY : function(el, xy) {
1982         el = Roo.fly(el, '_setXY');
1983         el.position();
1984         var pts = el.translatePoints(xy);
1985         if (xy[0] !== false) {
1986             el.dom.style.left = pts.left + "px";
1987         }
1988         if (xy[1] !== false) {
1989             el.dom.style.top = pts.top + "px";
1990         }
1991     },
1992
1993     setX : function(el, x) {
1994         this.setXY(el, [x, false]);
1995     },
1996
1997     setY : function(el, y) {
1998         this.setXY(el, [false, y]);
1999     }
2000 };
2001 /*
2002  * Portions of this file are based on pieces of Yahoo User Interface Library
2003  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2004  * YUI licensed under the BSD License:
2005  * http://developer.yahoo.net/yui/license.txt
2006  * <script type="text/javascript">
2007  *
2008  */
2009
2010 Roo.lib.Event = function() {
2011     var loadComplete = false;
2012     var listeners = [];
2013     var unloadListeners = [];
2014     var retryCount = 0;
2015     var onAvailStack = [];
2016     var counter = 0;
2017     var lastError = null;
2018
2019     return {
2020         POLL_RETRYS: 200,
2021         POLL_INTERVAL: 20,
2022         EL: 0,
2023         TYPE: 1,
2024         FN: 2,
2025         WFN: 3,
2026         OBJ: 3,
2027         ADJ_SCOPE: 4,
2028         _interval: null,
2029
2030         startInterval: function() {
2031             if (!this._interval) {
2032                 var self = this;
2033                 var callback = function() {
2034                     self._tryPreloadAttach();
2035                 };
2036                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2037
2038             }
2039         },
2040
2041         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2042             onAvailStack.push({ id:         p_id,
2043                 fn:         p_fn,
2044                 obj:        p_obj,
2045                 override:   p_override,
2046                 checkReady: false    });
2047
2048             retryCount = this.POLL_RETRYS;
2049             this.startInterval();
2050         },
2051
2052
2053         addListener: function(el, eventName, fn) {
2054             el = Roo.getDom(el);
2055             if (!el || !fn) {
2056                 return false;
2057             }
2058
2059             if ("unload" == eventName) {
2060                 unloadListeners[unloadListeners.length] =
2061                 [el, eventName, fn];
2062                 return true;
2063             }
2064
2065             var wrappedFn = function(e) {
2066                 return fn(Roo.lib.Event.getEvent(e));
2067             };
2068
2069             var li = [el, eventName, fn, wrappedFn];
2070
2071             var index = listeners.length;
2072             listeners[index] = li;
2073
2074             this.doAdd(el, eventName, wrappedFn, false);
2075             return true;
2076
2077         },
2078
2079
2080         removeListener: function(el, eventName, fn) {
2081             var i, len;
2082
2083             el = Roo.getDom(el);
2084
2085             if(!fn) {
2086                 return this.purgeElement(el, false, eventName);
2087             }
2088
2089
2090             if ("unload" == eventName) {
2091
2092                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2093                     var li = unloadListeners[i];
2094                     if (li &&
2095                         li[0] == el &&
2096                         li[1] == eventName &&
2097                         li[2] == fn) {
2098                         unloadListeners.splice(i, 1);
2099                         return true;
2100                     }
2101                 }
2102
2103                 return false;
2104             }
2105
2106             var cacheItem = null;
2107
2108
2109             var index = arguments[3];
2110
2111             if ("undefined" == typeof index) {
2112                 index = this._getCacheIndex(el, eventName, fn);
2113             }
2114
2115             if (index >= 0) {
2116                 cacheItem = listeners[index];
2117             }
2118
2119             if (!el || !cacheItem) {
2120                 return false;
2121             }
2122
2123             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2124
2125             delete listeners[index][this.WFN];
2126             delete listeners[index][this.FN];
2127             listeners.splice(index, 1);
2128
2129             return true;
2130
2131         },
2132
2133
2134         getTarget: function(ev, resolveTextNode) {
2135             ev = ev.browserEvent || ev;
2136             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2137             var t = ev.target || ev.srcElement;
2138             return this.resolveTextNode(t);
2139         },
2140
2141
2142         resolveTextNode: function(node) {
2143             if (Roo.isSafari && node && 3 == node.nodeType) {
2144                 return node.parentNode;
2145             } else {
2146                 return node;
2147             }
2148         },
2149
2150
2151         getPageX: function(ev) {
2152             ev = ev.browserEvent || ev;
2153             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2154             var x = ev.pageX;
2155             if (!x && 0 !== x) {
2156                 x = ev.clientX || 0;
2157
2158                 if (Roo.isIE) {
2159                     x += this.getScroll()[1];
2160                 }
2161             }
2162
2163             return x;
2164         },
2165
2166
2167         getPageY: function(ev) {
2168             ev = ev.browserEvent || ev;
2169             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2170             var y = ev.pageY;
2171             if (!y && 0 !== y) {
2172                 y = ev.clientY || 0;
2173
2174                 if (Roo.isIE) {
2175                     y += this.getScroll()[0];
2176                 }
2177             }
2178
2179
2180             return y;
2181         },
2182
2183
2184         getXY: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             return [this.getPageX(ev), this.getPageY(ev)];
2188         },
2189
2190
2191         getRelatedTarget: function(ev) {
2192             ev = ev.browserEvent || ev;
2193             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2194             var t = ev.relatedTarget;
2195             if (!t) {
2196                 if (ev.type == "mouseout") {
2197                     t = ev.toElement;
2198                 } else if (ev.type == "mouseover") {
2199                     t = ev.fromElement;
2200                 }
2201             }
2202
2203             return this.resolveTextNode(t);
2204         },
2205
2206
2207         getTime: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2210             if (!ev.time) {
2211                 var t = new Date().getTime();
2212                 try {
2213                     ev.time = t;
2214                 } catch(ex) {
2215                     this.lastError = ex;
2216                     return t;
2217                 }
2218             }
2219
2220             return ev.time;
2221         },
2222
2223
2224         stopEvent: function(ev) {
2225             this.stopPropagation(ev);
2226             this.preventDefault(ev);
2227         },
2228
2229
2230         stopPropagation: function(ev) {
2231             ev = ev.browserEvent || ev;
2232             if (ev.stopPropagation) {
2233                 ev.stopPropagation();
2234             } else {
2235                 ev.cancelBubble = true;
2236             }
2237         },
2238
2239
2240         preventDefault: function(ev) {
2241             ev = ev.browserEvent || ev;
2242             if(ev.preventDefault) {
2243                 ev.preventDefault();
2244             } else {
2245                 ev.returnValue = false;
2246             }
2247         },
2248
2249
2250         getEvent: function(e) {
2251             var ev = e || window.event;
2252             if (!ev) {
2253                 var c = this.getEvent.caller;
2254                 while (c) {
2255                     ev = c.arguments[0];
2256                     if (ev && Event == ev.constructor) {
2257                         break;
2258                     }
2259                     c = c.caller;
2260                 }
2261             }
2262             return ev;
2263         },
2264
2265
2266         getCharCode: function(ev) {
2267             ev = ev.browserEvent || ev;
2268             return ev.charCode || ev.keyCode || 0;
2269         },
2270
2271
2272         _getCacheIndex: function(el, eventName, fn) {
2273             for (var i = 0,len = listeners.length; i < len; ++i) {
2274                 var li = listeners[i];
2275                 if (li &&
2276                     li[this.FN] == fn &&
2277                     li[this.EL] == el &&
2278                     li[this.TYPE] == eventName) {
2279                     return i;
2280                 }
2281             }
2282
2283             return -1;
2284         },
2285
2286
2287         elCache: {},
2288
2289
2290         getEl: function(id) {
2291             return document.getElementById(id);
2292         },
2293
2294
2295         clearCache: function() {
2296         },
2297
2298
2299         _load: function(e) {
2300             loadComplete = true;
2301             var EU = Roo.lib.Event;
2302
2303
2304             if (Roo.isIE) {
2305                 EU.doRemove(window, "load", EU._load);
2306             }
2307         },
2308
2309
2310         _tryPreloadAttach: function() {
2311
2312             if (this.locked) {
2313                 return false;
2314             }
2315
2316             this.locked = true;
2317
2318
2319             var tryAgain = !loadComplete;
2320             if (!tryAgain) {
2321                 tryAgain = (retryCount > 0);
2322             }
2323
2324
2325             var notAvail = [];
2326             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2327                 var item = onAvailStack[i];
2328                 if (item) {
2329                     var el = this.getEl(item.id);
2330
2331                     if (el) {
2332                         if (!item.checkReady ||
2333                             loadComplete ||
2334                             el.nextSibling ||
2335                             (document && document.body)) {
2336
2337                             var scope = el;
2338                             if (item.override) {
2339                                 if (item.override === true) {
2340                                     scope = item.obj;
2341                                 } else {
2342                                     scope = item.override;
2343                                 }
2344                             }
2345                             item.fn.call(scope, item.obj);
2346                             onAvailStack[i] = null;
2347                         }
2348                     } else {
2349                         notAvail.push(item);
2350                     }
2351                 }
2352             }
2353
2354             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355
2356             if (tryAgain) {
2357
2358                 this.startInterval();
2359             } else {
2360                 clearInterval(this._interval);
2361                 this._interval = null;
2362             }
2363
2364             this.locked = false;
2365
2366             return true;
2367
2368         },
2369
2370
2371         purgeElement: function(el, recurse, eventName) {
2372             var elListeners = this.getListeners(el, eventName);
2373             if (elListeners) {
2374                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2375                     var l = elListeners[i];
2376                     this.removeListener(el, l.type, l.fn);
2377                 }
2378             }
2379
2380             if (recurse && el && el.childNodes) {
2381                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2382                     this.purgeElement(el.childNodes[i], recurse, eventName);
2383                 }
2384             }
2385         },
2386
2387
2388         getListeners: function(el, eventName) {
2389             var results = [], searchLists;
2390             if (!eventName) {
2391                 searchLists = [listeners, unloadListeners];
2392             } else if (eventName == "unload") {
2393                 searchLists = [unloadListeners];
2394             } else {
2395                 searchLists = [listeners];
2396             }
2397
2398             for (var j = 0; j < searchLists.length; ++j) {
2399                 var searchList = searchLists[j];
2400                 if (searchList && searchList.length > 0) {
2401                     for (var i = 0,len = searchList.length; i < len; ++i) {
2402                         var l = searchList[i];
2403                         if (l && l[this.EL] === el &&
2404                             (!eventName || eventName === l[this.TYPE])) {
2405                             results.push({
2406                                 type:   l[this.TYPE],
2407                                 fn:     l[this.FN],
2408                                 obj:    l[this.OBJ],
2409                                 adjust: l[this.ADJ_SCOPE],
2410                                 index:  i
2411                             });
2412                         }
2413                     }
2414                 }
2415             }
2416
2417             return (results.length) ? results : null;
2418         },
2419
2420
2421         _unload: function(e) {
2422
2423             var EU = Roo.lib.Event, i, j, l, len, index;
2424
2425             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2426                 l = unloadListeners[i];
2427                 if (l) {
2428                     var scope = window;
2429                     if (l[EU.ADJ_SCOPE]) {
2430                         if (l[EU.ADJ_SCOPE] === true) {
2431                             scope = l[EU.OBJ];
2432                         } else {
2433                             scope = l[EU.ADJ_SCOPE];
2434                         }
2435                     }
2436                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2437                     unloadListeners[i] = null;
2438                     l = null;
2439                     scope = null;
2440                 }
2441             }
2442
2443             unloadListeners = null;
2444
2445             if (listeners && listeners.length > 0) {
2446                 j = listeners.length;
2447                 while (j) {
2448                     index = j - 1;
2449                     l = listeners[index];
2450                     if (l) {
2451                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2452                                 l[EU.FN], index);
2453                     }
2454                     j = j - 1;
2455                 }
2456                 l = null;
2457
2458                 EU.clearCache();
2459             }
2460
2461             EU.doRemove(window, "unload", EU._unload);
2462
2463         },
2464
2465
2466         getScroll: function() {
2467             var dd = document.documentElement, db = document.body;
2468             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2469                 return [dd.scrollTop, dd.scrollLeft];
2470             } else if (db) {
2471                 return [db.scrollTop, db.scrollLeft];
2472             } else {
2473                 return [0, 0];
2474             }
2475         },
2476
2477
2478         doAdd: function () {
2479             if (window.addEventListener) {
2480                 return function(el, eventName, fn, capture) {
2481                     el.addEventListener(eventName, fn, (capture));
2482                 };
2483             } else if (window.attachEvent) {
2484                 return function(el, eventName, fn, capture) {
2485                     el.attachEvent("on" + eventName, fn);
2486                 };
2487             } else {
2488                 return function() {
2489                 };
2490             }
2491         }(),
2492
2493
2494         doRemove: function() {
2495             if (window.removeEventListener) {
2496                 return function (el, eventName, fn, capture) {
2497                     el.removeEventListener(eventName, fn, (capture));
2498                 };
2499             } else if (window.detachEvent) {
2500                 return function (el, eventName, fn) {
2501                     el.detachEvent("on" + eventName, fn);
2502                 };
2503             } else {
2504                 return function() {
2505                 };
2506             }
2507         }()
2508     };
2509     
2510 }();
2511 (function() {     
2512    
2513     var E = Roo.lib.Event;
2514     E.on = E.addListener;
2515     E.un = E.removeListener;
2516
2517     if (document && document.body) {
2518         E._load();
2519     } else {
2520         E.doAdd(window, "load", E._load);
2521     }
2522     E.doAdd(window, "unload", E._unload);
2523     E._tryPreloadAttach();
2524 })();
2525
2526 /*
2527  * Portions of this file are based on pieces of Yahoo User Interface Library
2528  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2529  * YUI licensed under the BSD License:
2530  * http://developer.yahoo.net/yui/license.txt
2531  * <script type="text/javascript">
2532  *
2533  */
2534
2535 (function() {
2536     /**
2537      * @class Roo.lib.Ajax
2538      *
2539      */
2540     Roo.lib.Ajax = {
2541         /**
2542          * @static 
2543          */
2544         request : function(method, uri, cb, data, options) {
2545             if(options){
2546                 var hs = options.headers;
2547                 if(hs){
2548                     for(var h in hs){
2549                         if(hs.hasOwnProperty(h)){
2550                             this.initHeader(h, hs[h], false);
2551                         }
2552                     }
2553                 }
2554                 if(options.xmlData){
2555                     this.initHeader('Content-Type', 'text/xml', false);
2556                     method = 'POST';
2557                     data = options.xmlData;
2558                 }
2559             }
2560
2561             return this.asyncRequest(method, uri, cb, data);
2562         },
2563
2564         serializeForm : function(form) {
2565             if(typeof form == 'string') {
2566                 form = (document.getElementById(form) || document.forms[form]);
2567             }
2568
2569             var el, name, val, disabled, data = '', hasSubmit = false;
2570             for (var i = 0; i < form.elements.length; i++) {
2571                 el = form.elements[i];
2572                 disabled = form.elements[i].disabled;
2573                 name = form.elements[i].name;
2574                 val = form.elements[i].value;
2575
2576                 if (!disabled && name){
2577                     switch (el.type)
2578                             {
2579                         case 'select-one':
2580                         case 'select-multiple':
2581                             for (var j = 0; j < el.options.length; j++) {
2582                                 if (el.options[j].selected) {
2583                                     if (Roo.isIE) {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                     else {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                 }
2590                             }
2591                             break;
2592                         case 'radio':
2593                         case 'checkbox':
2594                             if (el.checked) {
2595                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596                             }
2597                             break;
2598                         case 'file':
2599
2600                         case undefined:
2601
2602                         case 'reset':
2603
2604                         case 'button':
2605
2606                             break;
2607                         case 'submit':
2608                             if(hasSubmit == false) {
2609                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2610                                 hasSubmit = true;
2611                             }
2612                             break;
2613                         default:
2614                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2615                             break;
2616                     }
2617                 }
2618             }
2619             data = data.substr(0, data.length - 1);
2620             return data;
2621         },
2622
2623         headers:{},
2624
2625         hasHeaders:false,
2626
2627         useDefaultHeader:true,
2628
2629         defaultPostHeader:'application/x-www-form-urlencoded',
2630
2631         useDefaultXhrHeader:true,
2632
2633         defaultXhrHeader:'XMLHttpRequest',
2634
2635         hasDefaultHeaders:true,
2636
2637         defaultHeaders:{},
2638
2639         poll:{},
2640
2641         timeout:{},
2642
2643         pollInterval:50,
2644
2645         transactionId:0,
2646
2647         setProgId:function(id)
2648         {
2649             this.activeX.unshift(id);
2650         },
2651
2652         setDefaultPostHeader:function(b)
2653         {
2654             this.useDefaultHeader = b;
2655         },
2656
2657         setDefaultXhrHeader:function(b)
2658         {
2659             this.useDefaultXhrHeader = b;
2660         },
2661
2662         setPollingInterval:function(i)
2663         {
2664             if (typeof i == 'number' && isFinite(i)) {
2665                 this.pollInterval = i;
2666             }
2667         },
2668
2669         createXhrObject:function(transactionId)
2670         {
2671             var obj,http;
2672             try
2673             {
2674
2675                 http = new XMLHttpRequest();
2676
2677                 obj = { conn:http, tId:transactionId };
2678             }
2679             catch(e)
2680             {
2681                 for (var i = 0; i < this.activeX.length; ++i) {
2682                     try
2683                     {
2684
2685                         http = new ActiveXObject(this.activeX[i]);
2686
2687                         obj = { conn:http, tId:transactionId };
2688                         break;
2689                     }
2690                     catch(e) {
2691                     }
2692                 }
2693             }
2694             finally
2695             {
2696                 return obj;
2697             }
2698         },
2699
2700         getConnectionObject:function()
2701         {
2702             var o;
2703             var tId = this.transactionId;
2704
2705             try
2706             {
2707                 o = this.createXhrObject(tId);
2708                 if (o) {
2709                     this.transactionId++;
2710                 }
2711             }
2712             catch(e) {
2713             }
2714             finally
2715             {
2716                 return o;
2717             }
2718         },
2719
2720         asyncRequest:function(method, uri, callback, postData)
2721         {
2722             var o = this.getConnectionObject();
2723
2724             if (!o) {
2725                 return null;
2726             }
2727             else {
2728                 o.conn.open(method, uri, true);
2729
2730                 if (this.useDefaultXhrHeader) {
2731                     if (!this.defaultHeaders['X-Requested-With']) {
2732                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733                     }
2734                 }
2735
2736                 if(postData && this.useDefaultHeader){
2737                     this.initHeader('Content-Type', this.defaultPostHeader);
2738                 }
2739
2740                  if (this.hasDefaultHeaders || this.hasHeaders) {
2741                     this.setHeader(o);
2742                 }
2743
2744                 this.handleReadyState(o, callback);
2745                 o.conn.send(postData || null);
2746
2747                 return o;
2748             }
2749         },
2750
2751         handleReadyState:function(o, callback)
2752         {
2753             var oConn = this;
2754
2755             if (callback && callback.timeout) {
2756                 
2757                 this.timeout[o.tId] = window.setTimeout(function() {
2758                     oConn.abort(o, callback, true);
2759                 }, callback.timeout);
2760             }
2761
2762             this.poll[o.tId] = window.setInterval(
2763                     function() {
2764                         if (o.conn && o.conn.readyState == 4) {
2765                             window.clearInterval(oConn.poll[o.tId]);
2766                             delete oConn.poll[o.tId];
2767
2768                             if(callback && callback.timeout) {
2769                                 window.clearTimeout(oConn.timeout[o.tId]);
2770                                 delete oConn.timeout[o.tId];
2771                             }
2772
2773                             oConn.handleTransactionResponse(o, callback);
2774                         }
2775                     }
2776                     , this.pollInterval);
2777         },
2778
2779         handleTransactionResponse:function(o, callback, isAbort)
2780         {
2781
2782             if (!callback) {
2783                 this.releaseObject(o);
2784                 return;
2785             }
2786
2787             var httpStatus, responseObject;
2788
2789             try
2790             {
2791                 if (o.conn.status !== undefined && o.conn.status != 0) {
2792                     httpStatus = o.conn.status;
2793                 }
2794                 else {
2795                     httpStatus = 13030;
2796                 }
2797             }
2798             catch(e) {
2799
2800
2801                 httpStatus = 13030;
2802             }
2803
2804             if (httpStatus >= 200 && httpStatus < 300) {
2805                 responseObject = this.createResponseObject(o, callback.argument);
2806                 if (callback.success) {
2807                     if (!callback.scope) {
2808                         callback.success(responseObject);
2809                     }
2810                     else {
2811
2812
2813                         callback.success.apply(callback.scope, [responseObject]);
2814                     }
2815                 }
2816             }
2817             else {
2818                 switch (httpStatus) {
2819
2820                     case 12002:
2821                     case 12029:
2822                     case 12030:
2823                     case 12031:
2824                     case 12152:
2825                     case 13030:
2826                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2827                         if (callback.failure) {
2828                             if (!callback.scope) {
2829                                 callback.failure(responseObject);
2830                             }
2831                             else {
2832                                 callback.failure.apply(callback.scope, [responseObject]);
2833                             }
2834                         }
2835                         break;
2836                     default:
2837                         responseObject = this.createResponseObject(o, callback.argument);
2838                         if (callback.failure) {
2839                             if (!callback.scope) {
2840                                 callback.failure(responseObject);
2841                             }
2842                             else {
2843                                 callback.failure.apply(callback.scope, [responseObject]);
2844                             }
2845                         }
2846                 }
2847             }
2848
2849             this.releaseObject(o);
2850             responseObject = null;
2851         },
2852
2853         createResponseObject:function(o, callbackArg)
2854         {
2855             var obj = {};
2856             var headerObj = {};
2857
2858             try
2859             {
2860                 var headerStr = o.conn.getAllResponseHeaders();
2861                 var header = headerStr.split('\n');
2862                 for (var i = 0; i < header.length; i++) {
2863                     var delimitPos = header[i].indexOf(':');
2864                     if (delimitPos != -1) {
2865                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2866                     }
2867                 }
2868             }
2869             catch(e) {
2870             }
2871
2872             obj.tId = o.tId;
2873             obj.status = o.conn.status;
2874             obj.statusText = o.conn.statusText;
2875             obj.getResponseHeader = headerObj;
2876             obj.getAllResponseHeaders = headerStr;
2877             obj.responseText = o.conn.responseText;
2878             obj.responseXML = o.conn.responseXML;
2879
2880             if (typeof callbackArg !== undefined) {
2881                 obj.argument = callbackArg;
2882             }
2883
2884             return obj;
2885         },
2886
2887         createExceptionObject:function(tId, callbackArg, isAbort)
2888         {
2889             var COMM_CODE = 0;
2890             var COMM_ERROR = 'communication failure';
2891             var ABORT_CODE = -1;
2892             var ABORT_ERROR = 'transaction aborted';
2893
2894             var obj = {};
2895
2896             obj.tId = tId;
2897             if (isAbort) {
2898                 obj.status = ABORT_CODE;
2899                 obj.statusText = ABORT_ERROR;
2900             }
2901             else {
2902                 obj.status = COMM_CODE;
2903                 obj.statusText = COMM_ERROR;
2904             }
2905
2906             if (callbackArg) {
2907                 obj.argument = callbackArg;
2908             }
2909
2910             return obj;
2911         },
2912
2913         initHeader:function(label, value, isDefault)
2914         {
2915             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2916
2917             if (headerObj[label] === undefined) {
2918                 headerObj[label] = value;
2919             }
2920             else {
2921
2922
2923                 headerObj[label] = value + "," + headerObj[label];
2924             }
2925
2926             if (isDefault) {
2927                 this.hasDefaultHeaders = true;
2928             }
2929             else {
2930                 this.hasHeaders = true;
2931             }
2932         },
2933
2934
2935         setHeader:function(o)
2936         {
2937             if (this.hasDefaultHeaders) {
2938                 for (var prop in this.defaultHeaders) {
2939                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2940                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2941                     }
2942                 }
2943             }
2944
2945             if (this.hasHeaders) {
2946                 for (var prop in this.headers) {
2947                     if (this.headers.hasOwnProperty(prop)) {
2948                         o.conn.setRequestHeader(prop, this.headers[prop]);
2949                     }
2950                 }
2951                 this.headers = {};
2952                 this.hasHeaders = false;
2953             }
2954         },
2955
2956         resetDefaultHeaders:function() {
2957             delete this.defaultHeaders;
2958             this.defaultHeaders = {};
2959             this.hasDefaultHeaders = false;
2960         },
2961
2962         abort:function(o, callback, isTimeout)
2963         {
2964             if(this.isCallInProgress(o)) {
2965                 o.conn.abort();
2966                 window.clearInterval(this.poll[o.tId]);
2967                 delete this.poll[o.tId];
2968                 if (isTimeout) {
2969                     delete this.timeout[o.tId];
2970                 }
2971
2972                 this.handleTransactionResponse(o, callback, true);
2973
2974                 return true;
2975             }
2976             else {
2977                 return false;
2978             }
2979         },
2980
2981
2982         isCallInProgress:function(o)
2983         {
2984             if (o && o.conn) {
2985                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2986             }
2987             else {
2988
2989                 return false;
2990             }
2991         },
2992
2993
2994         releaseObject:function(o)
2995         {
2996
2997             o.conn = null;
2998
2999             o = null;
3000         },
3001
3002         activeX:[
3003         'MSXML2.XMLHTTP.3.0',
3004         'MSXML2.XMLHTTP',
3005         'Microsoft.XMLHTTP'
3006         ]
3007
3008
3009     };
3010 })();/*
3011  * Portions of this file are based on pieces of Yahoo User Interface Library
3012  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3013  * YUI licensed under the BSD License:
3014  * http://developer.yahoo.net/yui/license.txt
3015  * <script type="text/javascript">
3016  *
3017  */
3018
3019 Roo.lib.Region = function(t, r, b, l) {
3020     this.top = t;
3021     this[1] = t;
3022     this.right = r;
3023     this.bottom = b;
3024     this.left = l;
3025     this[0] = l;
3026 };
3027
3028
3029 Roo.lib.Region.prototype = {
3030     contains : function(region) {
3031         return ( region.left >= this.left &&
3032                  region.right <= this.right &&
3033                  region.top >= this.top &&
3034                  region.bottom <= this.bottom    );
3035
3036     },
3037
3038     getArea : function() {
3039         return ( (this.bottom - this.top) * (this.right - this.left) );
3040     },
3041
3042     intersect : function(region) {
3043         var t = Math.max(this.top, region.top);
3044         var r = Math.min(this.right, region.right);
3045         var b = Math.min(this.bottom, region.bottom);
3046         var l = Math.max(this.left, region.left);
3047
3048         if (b >= t && r >= l) {
3049             return new Roo.lib.Region(t, r, b, l);
3050         } else {
3051             return null;
3052         }
3053     },
3054     union : function(region) {
3055         var t = Math.min(this.top, region.top);
3056         var r = Math.max(this.right, region.right);
3057         var b = Math.max(this.bottom, region.bottom);
3058         var l = Math.min(this.left, region.left);
3059
3060         return new Roo.lib.Region(t, r, b, l);
3061     },
3062
3063     adjust : function(t, l, b, r) {
3064         this.top += t;
3065         this.left += l;
3066         this.right += r;
3067         this.bottom += b;
3068         return this;
3069     }
3070 };
3071
3072 Roo.lib.Region.getRegion = function(el) {
3073     var p = Roo.lib.Dom.getXY(el);
3074
3075     var t = p[1];
3076     var r = p[0] + el.offsetWidth;
3077     var b = p[1] + el.offsetHeight;
3078     var l = p[0];
3079
3080     return new Roo.lib.Region(t, r, b, l);
3081 };
3082 /*
3083  * Portions of this file are based on pieces of Yahoo User Interface Library
3084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3085  * YUI licensed under the BSD License:
3086  * http://developer.yahoo.net/yui/license.txt
3087  * <script type="text/javascript">
3088  *
3089  */
3090 //@@dep Roo.lib.Region
3091
3092
3093 Roo.lib.Point = function(x, y) {
3094     if (x instanceof Array) {
3095         y = x[1];
3096         x = x[0];
3097     }
3098     this.x = this.right = this.left = this[0] = x;
3099     this.y = this.top = this.bottom = this[1] = y;
3100 };
3101
3102 Roo.lib.Point.prototype = new Roo.lib.Region();
3103 /*
3104  * Portions of this file are based on pieces of Yahoo User Interface Library
3105  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3106  * YUI licensed under the BSD License:
3107  * http://developer.yahoo.net/yui/license.txt
3108  * <script type="text/javascript">
3109  *
3110  */
3111  
3112 (function() {   
3113
3114     Roo.lib.Anim = {
3115         scroll : function(el, args, duration, easing, cb, scope) {
3116             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3117         },
3118
3119         motion : function(el, args, duration, easing, cb, scope) {
3120             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3121         },
3122
3123         color : function(el, args, duration, easing, cb, scope) {
3124             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3125         },
3126
3127         run : function(el, args, duration, easing, cb, scope, type) {
3128             type = type || Roo.lib.AnimBase;
3129             if (typeof easing == "string") {
3130                 easing = Roo.lib.Easing[easing];
3131             }
3132             var anim = new type(el, args, duration, easing);
3133             anim.animateX(function() {
3134                 Roo.callback(cb, scope);
3135             });
3136             return anim;
3137         }
3138     };
3139 })();/*
3140  * Portions of this file are based on pieces of Yahoo User Interface Library
3141  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3142  * YUI licensed under the BSD License:
3143  * http://developer.yahoo.net/yui/license.txt
3144  * <script type="text/javascript">
3145  *
3146  */
3147
3148 (function() {    
3149     var libFlyweight;
3150     
3151     function fly(el) {
3152         if (!libFlyweight) {
3153             libFlyweight = new Roo.Element.Flyweight();
3154         }
3155         libFlyweight.dom = el;
3156         return libFlyweight;
3157     }
3158
3159     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160     
3161    
3162     
3163     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3164         if (el) {
3165             this.init(el, attributes, duration, method);
3166         }
3167     };
3168
3169     Roo.lib.AnimBase.fly = fly;
3170     
3171     
3172     
3173     Roo.lib.AnimBase.prototype = {
3174
3175         toString: function() {
3176             var el = this.getEl();
3177             var id = el.id || el.tagName;
3178             return ("Anim " + id);
3179         },
3180
3181         patterns: {
3182             noNegatives:        /width|height|opacity|padding/i,
3183             offsetAttribute:  /^((width|height)|(top|left))$/,
3184             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3185             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186         },
3187
3188
3189         doMethod: function(attr, start, end) {
3190             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191         },
3192
3193
3194         setAttribute: function(attr, val, unit) {
3195             if (this.patterns.noNegatives.test(attr)) {
3196                 val = (val > 0) ? val : 0;
3197             }
3198
3199             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200         },
3201
3202
3203         getAttribute: function(attr) {
3204             var el = this.getEl();
3205             var val = fly(el).getStyle(attr);
3206
3207             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3208                 return parseFloat(val);
3209             }
3210
3211             var a = this.patterns.offsetAttribute.exec(attr) || [];
3212             var pos = !!( a[3] );
3213             var box = !!( a[2] );
3214
3215
3216             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3217                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3218             } else {
3219                 val = 0;
3220             }
3221
3222             return val;
3223         },
3224
3225
3226         getDefaultUnit: function(attr) {
3227             if (this.patterns.defaultUnit.test(attr)) {
3228                 return 'px';
3229             }
3230
3231             return '';
3232         },
3233
3234         animateX : function(callback, scope) {
3235             var f = function() {
3236                 this.onComplete.removeListener(f);
3237                 if (typeof callback == "function") {
3238                     callback.call(scope || this, this);
3239                 }
3240             };
3241             this.onComplete.addListener(f, this);
3242             this.animate();
3243         },
3244
3245
3246         setRuntimeAttribute: function(attr) {
3247             var start;
3248             var end;
3249             var attributes = this.attributes;
3250
3251             this.runtimeAttributes[attr] = {};
3252
3253             var isset = function(prop) {
3254                 return (typeof prop !== 'undefined');
3255             };
3256
3257             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258                 return false;
3259             }
3260
3261             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3262
3263
3264             if (isset(attributes[attr]['to'])) {
3265                 end = attributes[attr]['to'];
3266             } else if (isset(attributes[attr]['by'])) {
3267                 if (start.constructor == Array) {
3268                     end = [];
3269                     for (var i = 0, len = start.length; i < len; ++i) {
3270                         end[i] = start[i] + attributes[attr]['by'][i];
3271                     }
3272                 } else {
3273                     end = start + attributes[attr]['by'];
3274                 }
3275             }
3276
3277             this.runtimeAttributes[attr].start = start;
3278             this.runtimeAttributes[attr].end = end;
3279
3280
3281             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282         },
3283
3284
3285         init: function(el, attributes, duration, method) {
3286
3287             var isAnimated = false;
3288
3289
3290             var startTime = null;
3291
3292
3293             var actualFrames = 0;
3294
3295
3296             el = Roo.getDom(el);
3297
3298
3299             this.attributes = attributes || {};
3300
3301
3302             this.duration = duration || 1;
3303
3304
3305             this.method = method || Roo.lib.Easing.easeNone;
3306
3307
3308             this.useSeconds = true;
3309
3310
3311             this.currentFrame = 0;
3312
3313
3314             this.totalFrames = Roo.lib.AnimMgr.fps;
3315
3316
3317             this.getEl = function() {
3318                 return el;
3319             };
3320
3321
3322             this.isAnimated = function() {
3323                 return isAnimated;
3324             };
3325
3326
3327             this.getStartTime = function() {
3328                 return startTime;
3329             };
3330
3331             this.runtimeAttributes = {};
3332
3333
3334             this.animate = function() {
3335                 if (this.isAnimated()) {
3336                     return false;
3337                 }
3338
3339                 this.currentFrame = 0;
3340
3341                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3342
3343                 Roo.lib.AnimMgr.registerElement(this);
3344             };
3345
3346
3347             this.stop = function(finish) {
3348                 if (finish) {
3349                     this.currentFrame = this.totalFrames;
3350                     this._onTween.fire();
3351                 }
3352                 Roo.lib.AnimMgr.stop(this);
3353             };
3354
3355             var onStart = function() {
3356                 this.onStart.fire();
3357
3358                 this.runtimeAttributes = {};
3359                 for (var attr in this.attributes) {
3360                     this.setRuntimeAttribute(attr);
3361                 }
3362
3363                 isAnimated = true;
3364                 actualFrames = 0;
3365                 startTime = new Date();
3366             };
3367
3368
3369             var onTween = function() {
3370                 var data = {
3371                     duration: new Date() - this.getStartTime(),
3372                     currentFrame: this.currentFrame
3373                 };
3374
3375                 data.toString = function() {
3376                     return (
3377                             'duration: ' + data.duration +
3378                             ', currentFrame: ' + data.currentFrame
3379                             );
3380                 };
3381
3382                 this.onTween.fire(data);
3383
3384                 var runtimeAttributes = this.runtimeAttributes;
3385
3386                 for (var attr in runtimeAttributes) {
3387                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3388                 }
3389
3390                 actualFrames += 1;
3391             };
3392
3393             var onComplete = function() {
3394                 var actual_duration = (new Date() - startTime) / 1000 ;
3395
3396                 var data = {
3397                     duration: actual_duration,
3398                     frames: actualFrames,
3399                     fps: actualFrames / actual_duration
3400                 };
3401
3402                 data.toString = function() {
3403                     return (
3404                             'duration: ' + data.duration +
3405                             ', frames: ' + data.frames +
3406                             ', fps: ' + data.fps
3407                             );
3408                 };
3409
3410                 isAnimated = false;
3411                 actualFrames = 0;
3412                 this.onComplete.fire(data);
3413             };
3414
3415
3416             this._onStart = new Roo.util.Event(this);
3417             this.onStart = new Roo.util.Event(this);
3418             this.onTween = new Roo.util.Event(this);
3419             this._onTween = new Roo.util.Event(this);
3420             this.onComplete = new Roo.util.Event(this);
3421             this._onComplete = new Roo.util.Event(this);
3422             this._onStart.addListener(onStart);
3423             this._onTween.addListener(onTween);
3424             this._onComplete.addListener(onComplete);
3425         }
3426     };
3427 })();
3428 /*
3429  * Portions of this file are based on pieces of Yahoo User Interface Library
3430  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3431  * YUI licensed under the BSD License:
3432  * http://developer.yahoo.net/yui/license.txt
3433  * <script type="text/javascript">
3434  *
3435  */
3436
3437 Roo.lib.AnimMgr = new function() {
3438
3439     var thread = null;
3440
3441
3442     var queue = [];
3443
3444
3445     var tweenCount = 0;
3446
3447
3448     this.fps = 1000;
3449
3450
3451     this.delay = 1;
3452
3453
3454     this.registerElement = function(tween) {
3455         queue[queue.length] = tween;
3456         tweenCount += 1;
3457         tween._onStart.fire();
3458         this.start();
3459     };
3460
3461
3462     this.unRegister = function(tween, index) {
3463         tween._onComplete.fire();
3464         index = index || getIndex(tween);
3465         if (index != -1) {
3466             queue.splice(index, 1);
3467         }
3468
3469         tweenCount -= 1;
3470         if (tweenCount <= 0) {
3471             this.stop();
3472         }
3473     };
3474
3475
3476     this.start = function() {
3477         if (thread === null) {
3478             thread = setInterval(this.run, this.delay);
3479         }
3480     };
3481
3482
3483     this.stop = function(tween) {
3484         if (!tween) {
3485             clearInterval(thread);
3486
3487             for (var i = 0, len = queue.length; i < len; ++i) {
3488                 if (queue[0].isAnimated()) {
3489                     this.unRegister(queue[0], 0);
3490                 }
3491             }
3492
3493             queue = [];
3494             thread = null;
3495             tweenCount = 0;
3496         }
3497         else {
3498             this.unRegister(tween);
3499         }
3500     };
3501
3502
3503     this.run = function() {
3504         for (var i = 0, len = queue.length; i < len; ++i) {
3505             var tween = queue[i];
3506             if (!tween || !tween.isAnimated()) {
3507                 continue;
3508             }
3509
3510             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3511             {
3512                 tween.currentFrame += 1;
3513
3514                 if (tween.useSeconds) {
3515                     correctFrame(tween);
3516                 }
3517                 tween._onTween.fire();
3518             }
3519             else {
3520                 Roo.lib.AnimMgr.stop(tween, i);
3521             }
3522         }
3523     };
3524
3525     var getIndex = function(anim) {
3526         for (var i = 0, len = queue.length; i < len; ++i) {
3527             if (queue[i] == anim) {
3528                 return i;
3529             }
3530         }
3531         return -1;
3532     };
3533
3534
3535     var correctFrame = function(tween) {
3536         var frames = tween.totalFrames;
3537         var frame = tween.currentFrame;
3538         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3539         var elapsed = (new Date() - tween.getStartTime());
3540         var tweak = 0;
3541
3542         if (elapsed < tween.duration * 1000) {
3543             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3544         } else {
3545             tweak = frames - (frame + 1);
3546         }
3547         if (tweak > 0 && isFinite(tweak)) {
3548             if (tween.currentFrame + tweak >= frames) {
3549                 tweak = frames - (frame + 1);
3550             }
3551
3552             tween.currentFrame += tweak;
3553         }
3554     };
3555 };
3556
3557     /*
3558  * Portions of this file are based on pieces of Yahoo User Interface Library
3559  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3560  * YUI licensed under the BSD License:
3561  * http://developer.yahoo.net/yui/license.txt
3562  * <script type="text/javascript">
3563  *
3564  */
3565 Roo.lib.Bezier = new function() {
3566
3567         this.getPosition = function(points, t) {
3568             var n = points.length;
3569             var tmp = [];
3570
3571             for (var i = 0; i < n; ++i) {
3572                 tmp[i] = [points[i][0], points[i][1]];
3573             }
3574
3575             for (var j = 1; j < n; ++j) {
3576                 for (i = 0; i < n - j; ++i) {
3577                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3578                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579                 }
3580             }
3581
3582             return [ tmp[0][0], tmp[0][1] ];
3583
3584         };
3585     };/*
3586  * Portions of this file are based on pieces of Yahoo User Interface Library
3587  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3588  * YUI licensed under the BSD License:
3589  * http://developer.yahoo.net/yui/license.txt
3590  * <script type="text/javascript">
3591  *
3592  */
3593 (function() {
3594
3595     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3596         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3597     };
3598
3599     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3600
3601     var fly = Roo.lib.AnimBase.fly;
3602     var Y = Roo.lib;
3603     var superclass = Y.ColorAnim.superclass;
3604     var proto = Y.ColorAnim.prototype;
3605
3606     proto.toString = function() {
3607         var el = this.getEl();
3608         var id = el.id || el.tagName;
3609         return ("ColorAnim " + id);
3610     };
3611
3612     proto.patterns.color = /color$/i;
3613     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3614     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3615     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3616     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3617
3618
3619     proto.parseColor = function(s) {
3620         if (s.length == 3) {
3621             return s;
3622         }
3623
3624         var c = this.patterns.hex.exec(s);
3625         if (c && c.length == 4) {
3626             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3627         }
3628
3629         c = this.patterns.rgb.exec(s);
3630         if (c && c.length == 4) {
3631             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3632         }
3633
3634         c = this.patterns.hex3.exec(s);
3635         if (c && c.length == 4) {
3636             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3637         }
3638
3639         return null;
3640     };
3641     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3642     proto.getAttribute = function(attr) {
3643         var el = this.getEl();
3644         if (this.patterns.color.test(attr)) {
3645             var val = fly(el).getStyle(attr);
3646
3647             if (this.patterns.transparent.test(val)) {
3648                 var parent = el.parentNode;
3649                 val = fly(parent).getStyle(attr);
3650
3651                 while (parent && this.patterns.transparent.test(val)) {
3652                     parent = parent.parentNode;
3653                     val = fly(parent).getStyle(attr);
3654                     if (parent.tagName.toUpperCase() == 'HTML') {
3655                         val = '#fff';
3656                     }
3657                 }
3658             }
3659         } else {
3660             val = superclass.getAttribute.call(this, attr);
3661         }
3662
3663         return val;
3664     };
3665     proto.getAttribute = function(attr) {
3666         var el = this.getEl();
3667         if (this.patterns.color.test(attr)) {
3668             var val = fly(el).getStyle(attr);
3669
3670             if (this.patterns.transparent.test(val)) {
3671                 var parent = el.parentNode;
3672                 val = fly(parent).getStyle(attr);
3673
3674                 while (parent && this.patterns.transparent.test(val)) {
3675                     parent = parent.parentNode;
3676                     val = fly(parent).getStyle(attr);
3677                     if (parent.tagName.toUpperCase() == 'HTML') {
3678                         val = '#fff';
3679                     }
3680                 }
3681             }
3682         } else {
3683             val = superclass.getAttribute.call(this, attr);
3684         }
3685
3686         return val;
3687     };
3688
3689     proto.doMethod = function(attr, start, end) {
3690         var val;
3691
3692         if (this.patterns.color.test(attr)) {
3693             val = [];
3694             for (var i = 0, len = start.length; i < len; ++i) {
3695                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3696             }
3697
3698             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3699         }
3700         else {
3701             val = superclass.doMethod.call(this, attr, start, end);
3702         }
3703
3704         return val;
3705     };
3706
3707     proto.setRuntimeAttribute = function(attr) {
3708         superclass.setRuntimeAttribute.call(this, attr);
3709
3710         if (this.patterns.color.test(attr)) {
3711             var attributes = this.attributes;
3712             var start = this.parseColor(this.runtimeAttributes[attr].start);
3713             var end = this.parseColor(this.runtimeAttributes[attr].end);
3714
3715             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3716                 end = this.parseColor(attributes[attr].by);
3717
3718                 for (var i = 0, len = start.length; i < len; ++i) {
3719                     end[i] = start[i] + end[i];
3720                 }
3721             }
3722
3723             this.runtimeAttributes[attr].start = start;
3724             this.runtimeAttributes[attr].end = end;
3725         }
3726     };
3727 })();
3728
3729 /*
3730  * Portions of this file are based on pieces of Yahoo User Interface Library
3731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732  * YUI licensed under the BSD License:
3733  * http://developer.yahoo.net/yui/license.txt
3734  * <script type="text/javascript">
3735  *
3736  */
3737 Roo.lib.Easing = {
3738
3739
3740     easeNone: function (t, b, c, d) {
3741         return c * t / d + b;
3742     },
3743
3744
3745     easeIn: function (t, b, c, d) {
3746         return c * (t /= d) * t + b;
3747     },
3748
3749
3750     easeOut: function (t, b, c, d) {
3751         return -c * (t /= d) * (t - 2) + b;
3752     },
3753
3754
3755     easeBoth: function (t, b, c, d) {
3756         if ((t /= d / 2) < 1) {
3757             return c / 2 * t * t + b;
3758         }
3759
3760         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761     },
3762
3763
3764     easeInStrong: function (t, b, c, d) {
3765         return c * (t /= d) * t * t * t + b;
3766     },
3767
3768
3769     easeOutStrong: function (t, b, c, d) {
3770         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771     },
3772
3773
3774     easeBothStrong: function (t, b, c, d) {
3775         if ((t /= d / 2) < 1) {
3776             return c / 2 * t * t * t * t + b;
3777         }
3778
3779         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3780     },
3781
3782
3783
3784     elasticIn: function (t, b, c, d, a, p) {
3785         if (t == 0) {
3786             return b;
3787         }
3788         if ((t /= d) == 1) {
3789             return b + c;
3790         }
3791         if (!p) {
3792             p = d * .3;
3793         }
3794
3795         if (!a || a < Math.abs(c)) {
3796             a = c;
3797             var s = p / 4;
3798         }
3799         else {
3800             var s = p / (2 * Math.PI) * Math.asin(c / a);
3801         }
3802
3803         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804     },
3805
3806
3807     elasticOut: function (t, b, c, d, a, p) {
3808         if (t == 0) {
3809             return b;
3810         }
3811         if ((t /= d) == 1) {
3812             return b + c;
3813         }
3814         if (!p) {
3815             p = d * .3;
3816         }
3817
3818         if (!a || a < Math.abs(c)) {
3819             a = c;
3820             var s = p / 4;
3821         }
3822         else {
3823             var s = p / (2 * Math.PI) * Math.asin(c / a);
3824         }
3825
3826         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827     },
3828
3829
3830     elasticBoth: function (t, b, c, d, a, p) {
3831         if (t == 0) {
3832             return b;
3833         }
3834
3835         if ((t /= d / 2) == 2) {
3836             return b + c;
3837         }
3838
3839         if (!p) {
3840             p = d * (.3 * 1.5);
3841         }
3842
3843         if (!a || a < Math.abs(c)) {
3844             a = c;
3845             var s = p / 4;
3846         }
3847         else {
3848             var s = p / (2 * Math.PI) * Math.asin(c / a);
3849         }
3850
3851         if (t < 1) {
3852             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3853                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3854         }
3855         return a * Math.pow(2, -10 * (t -= 1)) *
3856                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3857     },
3858
3859
3860
3861     backIn: function (t, b, c, d, s) {
3862         if (typeof s == 'undefined') {
3863             s = 1.70158;
3864         }
3865         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866     },
3867
3868
3869     backOut: function (t, b, c, d, s) {
3870         if (typeof s == 'undefined') {
3871             s = 1.70158;
3872         }
3873         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874     },
3875
3876
3877     backBoth: function (t, b, c, d, s) {
3878         if (typeof s == 'undefined') {
3879             s = 1.70158;
3880         }
3881
3882         if ((t /= d / 2 ) < 1) {
3883             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3884         }
3885         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886     },
3887
3888
3889     bounceIn: function (t, b, c, d) {
3890         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891     },
3892
3893
3894     bounceOut: function (t, b, c, d) {
3895         if ((t /= d) < (1 / 2.75)) {
3896             return c * (7.5625 * t * t) + b;
3897         } else if (t < (2 / 2.75)) {
3898             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3899         } else if (t < (2.5 / 2.75)) {
3900             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3901         }
3902         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903     },
3904
3905
3906     bounceBoth: function (t, b, c, d) {
3907         if (t < d / 2) {
3908             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3909         }
3910         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3911     }
3912 };/*
3913  * Portions of this file are based on pieces of Yahoo User Interface Library
3914  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3915  * YUI licensed under the BSD License:
3916  * http://developer.yahoo.net/yui/license.txt
3917  * <script type="text/javascript">
3918  *
3919  */
3920     (function() {
3921         Roo.lib.Motion = function(el, attributes, duration, method) {
3922             if (el) {
3923                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924             }
3925         };
3926
3927         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928
3929
3930         var Y = Roo.lib;
3931         var superclass = Y.Motion.superclass;
3932         var proto = Y.Motion.prototype;
3933
3934         proto.toString = function() {
3935             var el = this.getEl();
3936             var id = el.id || el.tagName;
3937             return ("Motion " + id);
3938         };
3939
3940         proto.patterns.points = /^points$/i;
3941
3942         proto.setAttribute = function(attr, val, unit) {
3943             if (this.patterns.points.test(attr)) {
3944                 unit = unit || 'px';
3945                 superclass.setAttribute.call(this, 'left', val[0], unit);
3946                 superclass.setAttribute.call(this, 'top', val[1], unit);
3947             } else {
3948                 superclass.setAttribute.call(this, attr, val, unit);
3949             }
3950         };
3951
3952         proto.getAttribute = function(attr) {
3953             if (this.patterns.points.test(attr)) {
3954                 var val = [
3955                         superclass.getAttribute.call(this, 'left'),
3956                         superclass.getAttribute.call(this, 'top')
3957                         ];
3958             } else {
3959                 val = superclass.getAttribute.call(this, attr);
3960             }
3961
3962             return val;
3963         };
3964
3965         proto.doMethod = function(attr, start, end) {
3966             var val = null;
3967
3968             if (this.patterns.points.test(attr)) {
3969                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3970                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3971             } else {
3972                 val = superclass.doMethod.call(this, attr, start, end);
3973             }
3974             return val;
3975         };
3976
3977         proto.setRuntimeAttribute = function(attr) {
3978             if (this.patterns.points.test(attr)) {
3979                 var el = this.getEl();
3980                 var attributes = this.attributes;
3981                 var start;
3982                 var control = attributes['points']['control'] || [];
3983                 var end;
3984                 var i, len;
3985
3986                 if (control.length > 0 && !(control[0] instanceof Array)) {
3987                     control = [control];
3988                 } else {
3989                     var tmp = [];
3990                     for (i = 0,len = control.length; i < len; ++i) {
3991                         tmp[i] = control[i];
3992                     }
3993                     control = tmp;
3994                 }
3995
3996                 Roo.fly(el).position();
3997
3998                 if (isset(attributes['points']['from'])) {
3999                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4000                 }
4001                 else {
4002                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4003                 }
4004
4005                 start = this.getAttribute('points');
4006
4007
4008                 if (isset(attributes['points']['to'])) {
4009                     end = translateValues.call(this, attributes['points']['to'], start);
4010
4011                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4012                     for (i = 0,len = control.length; i < len; ++i) {
4013                         control[i] = translateValues.call(this, control[i], start);
4014                     }
4015
4016
4017                 } else if (isset(attributes['points']['by'])) {
4018                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4019
4020                     for (i = 0,len = control.length; i < len; ++i) {
4021                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022                     }
4023                 }
4024
4025                 this.runtimeAttributes[attr] = [start];
4026
4027                 if (control.length > 0) {
4028                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4029                 }
4030
4031                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4032             }
4033             else {
4034                 superclass.setRuntimeAttribute.call(this, attr);
4035             }
4036         };
4037
4038         var translateValues = function(val, start) {
4039             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4040             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4041
4042             return val;
4043         };
4044
4045         var isset = function(prop) {
4046             return (typeof prop !== 'undefined');
4047         };
4048     })();
4049 /*
4050  * Portions of this file are based on pieces of Yahoo User Interface Library
4051  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4052  * YUI licensed under the BSD License:
4053  * http://developer.yahoo.net/yui/license.txt
4054  * <script type="text/javascript">
4055  *
4056  */
4057     (function() {
4058         Roo.lib.Scroll = function(el, attributes, duration, method) {
4059             if (el) {
4060                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061             }
4062         };
4063
4064         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065
4066
4067         var Y = Roo.lib;
4068         var superclass = Y.Scroll.superclass;
4069         var proto = Y.Scroll.prototype;
4070
4071         proto.toString = function() {
4072             var el = this.getEl();
4073             var id = el.id || el.tagName;
4074             return ("Scroll " + id);
4075         };
4076
4077         proto.doMethod = function(attr, start, end) {
4078             var val = null;
4079
4080             if (attr == 'scroll') {
4081                 val = [
4082                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4083                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084                         ];
4085
4086             } else {
4087                 val = superclass.doMethod.call(this, attr, start, end);
4088             }
4089             return val;
4090         };
4091
4092         proto.getAttribute = function(attr) {
4093             var val = null;
4094             var el = this.getEl();
4095
4096             if (attr == 'scroll') {
4097                 val = [ el.scrollLeft, el.scrollTop ];
4098             } else {
4099                 val = superclass.getAttribute.call(this, attr);
4100             }
4101
4102             return val;
4103         };
4104
4105         proto.setAttribute = function(attr, val, unit) {
4106             var el = this.getEl();
4107
4108             if (attr == 'scroll') {
4109                 el.scrollLeft = val[0];
4110                 el.scrollTop = val[1];
4111             } else {
4112                 superclass.setAttribute.call(this, attr, val, unit);
4113             }
4114         };
4115     })();
4116 /*
4117  * Based on:
4118  * Ext JS Library 1.1.1
4119  * Copyright(c) 2006-2007, Ext JS, LLC.
4120  *
4121  * Originally Released Under LGPL - original licence link has changed is not relivant.
4122  *
4123  * Fork - LGPL
4124  * <script type="text/javascript">
4125  */
4126
4127
4128 // nasty IE9 hack - what a pile of crap that is..
4129
4130  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4131     Range.prototype.createContextualFragment = function (html) {
4132         var doc = window.document;
4133         var container = doc.createElement("div");
4134         container.innerHTML = html;
4135         var frag = doc.createDocumentFragment(), n;
4136         while ((n = container.firstChild)) {
4137             frag.appendChild(n);
4138         }
4139         return frag;
4140     };
4141 }
4142
4143 /**
4144  * @class Roo.DomHelper
4145  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4146  * 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>.
4147  * @singleton
4148  */
4149 Roo.DomHelper = function(){
4150     var tempTableEl = null;
4151     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4152     var tableRe = /^table|tbody|tr|td$/i;
4153     var xmlns = {};
4154     // build as innerHTML where available
4155     /** @ignore */
4156     var createHtml = function(o){
4157         if(typeof o == 'string'){
4158             return o;
4159         }
4160         var b = "";
4161         if(!o.tag){
4162             o.tag = "div";
4163         }
4164         b += "<" + o.tag;
4165         for(var attr in o){
4166             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4167             if(attr == "style"){
4168                 var s = o["style"];
4169                 if(typeof s == "function"){
4170                     s = s.call();
4171                 }
4172                 if(typeof s == "string"){
4173                     b += ' style="' + s + '"';
4174                 }else if(typeof s == "object"){
4175                     b += ' style="';
4176                     for(var key in s){
4177                         if(typeof s[key] != "function"){
4178                             b += key + ":" + s[key] + ";";
4179                         }
4180                     }
4181                     b += '"';
4182                 }
4183             }else{
4184                 if(attr == "cls"){
4185                     b += ' class="' + o["cls"] + '"';
4186                 }else if(attr == "htmlFor"){
4187                     b += ' for="' + o["htmlFor"] + '"';
4188                 }else{
4189                     b += " " + attr + '="' + o[attr] + '"';
4190                 }
4191             }
4192         }
4193         if(emptyTags.test(o.tag)){
4194             b += "/>";
4195         }else{
4196             b += ">";
4197             var cn = o.children || o.cn;
4198             if(cn){
4199                 //http://bugs.kde.org/show_bug.cgi?id=71506
4200                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4201                     for(var i = 0, len = cn.length; i < len; i++) {
4202                         b += createHtml(cn[i], b);
4203                     }
4204                 }else{
4205                     b += createHtml(cn, b);
4206                 }
4207             }
4208             if(o.html){
4209                 b += o.html;
4210             }
4211             b += "</" + o.tag + ">";
4212         }
4213         return b;
4214     };
4215
4216     // build as dom
4217     /** @ignore */
4218     var createDom = function(o, parentNode){
4219          
4220         // defininition craeted..
4221         var ns = false;
4222         if (o.ns && o.ns != 'html') {
4223                
4224             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4225                 xmlns[o.ns] = o.xmlns;
4226                 ns = o.xmlns;
4227             }
4228             if (typeof(xmlns[o.ns]) == 'undefined') {
4229                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4230             }
4231             ns = xmlns[o.ns];
4232         }
4233         
4234         
4235         if (typeof(o) == 'string') {
4236             return parentNode.appendChild(document.createTextNode(o));
4237         }
4238         o.tag = o.tag || div;
4239         if (o.ns && Roo.isIE) {
4240             ns = false;
4241             o.tag = o.ns + ':' + o.tag;
4242             
4243         }
4244         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4245         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4246         for(var attr in o){
4247             
4248             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4249                     attr == "style" || typeof o[attr] == "function") { continue; }
4250                     
4251             if(attr=="cls" && Roo.isIE){
4252                 el.className = o["cls"];
4253             }else{
4254                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4255                 else { 
4256                     el[attr] = o[attr];
4257                 }
4258             }
4259         }
4260         Roo.DomHelper.applyStyles(el, o.style);
4261         var cn = o.children || o.cn;
4262         if(cn){
4263             //http://bugs.kde.org/show_bug.cgi?id=71506
4264              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4265                 for(var i = 0, len = cn.length; i < len; i++) {
4266                     createDom(cn[i], el);
4267                 }
4268             }else{
4269                 createDom(cn, el);
4270             }
4271         }
4272         if(o.html){
4273             el.innerHTML = o.html;
4274         }
4275         if(parentNode){
4276            parentNode.appendChild(el);
4277         }
4278         return el;
4279     };
4280
4281     var ieTable = function(depth, s, h, e){
4282         tempTableEl.innerHTML = [s, h, e].join('');
4283         var i = -1, el = tempTableEl;
4284         while(++i < depth){
4285             el = el.firstChild;
4286         }
4287         return el;
4288     };
4289
4290     // kill repeat to save bytes
4291     var ts = '<table>',
4292         te = '</table>',
4293         tbs = ts+'<tbody>',
4294         tbe = '</tbody>'+te,
4295         trs = tbs + '<tr>',
4296         tre = '</tr>'+tbe;
4297
4298     /**
4299      * @ignore
4300      * Nasty code for IE's broken table implementation
4301      */
4302     var insertIntoTable = function(tag, where, el, html){
4303         if(!tempTableEl){
4304             tempTableEl = document.createElement('div');
4305         }
4306         var node;
4307         var before = null;
4308         if(tag == 'td'){
4309             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4310                 return;
4311             }
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315             } else{
4316                 before = el.nextSibling;
4317                 el = el.parentNode;
4318             }
4319             node = ieTable(4, trs, html, tre);
4320         }
4321         else if(tag == 'tr'){
4322             if(where == 'beforebegin'){
4323                 before = el;
4324                 el = el.parentNode;
4325                 node = ieTable(3, tbs, html, tbe);
4326             } else if(where == 'afterend'){
4327                 before = el.nextSibling;
4328                 el = el.parentNode;
4329                 node = ieTable(3, tbs, html, tbe);
4330             } else{ // INTO a TR
4331                 if(where == 'afterbegin'){
4332                     before = el.firstChild;
4333                 }
4334                 node = ieTable(4, trs, html, tre);
4335             }
4336         } else if(tag == 'tbody'){
4337             if(where == 'beforebegin'){
4338                 before = el;
4339                 el = el.parentNode;
4340                 node = ieTable(2, ts, html, te);
4341             } else if(where == 'afterend'){
4342                 before = el.nextSibling;
4343                 el = el.parentNode;
4344                 node = ieTable(2, ts, html, te);
4345             } else{
4346                 if(where == 'afterbegin'){
4347                     before = el.firstChild;
4348                 }
4349                 node = ieTable(3, tbs, html, tbe);
4350             }
4351         } else{ // TABLE
4352             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4353                 return;
4354             }
4355             if(where == 'afterbegin'){
4356                 before = el.firstChild;
4357             }
4358             node = ieTable(2, ts, html, te);
4359         }
4360         el.insertBefore(node, before);
4361         return node;
4362     };
4363
4364     return {
4365     /** True to force the use of DOM instead of html fragments @type Boolean */
4366     useDom : false,
4367
4368     /**
4369      * Returns the markup for the passed Element(s) config
4370      * @param {Object} o The Dom object spec (and children)
4371      * @return {String}
4372      */
4373     markup : function(o){
4374         return createHtml(o);
4375     },
4376
4377     /**
4378      * Applies a style specification to an element
4379      * @param {String/HTMLElement} el The element to apply styles to
4380      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4381      * a function which returns such a specification.
4382      */
4383     applyStyles : function(el, styles){
4384         if(styles){
4385            el = Roo.fly(el);
4386            if(typeof styles == "string"){
4387                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4388                var matches;
4389                while ((matches = re.exec(styles)) != null){
4390                    el.setStyle(matches[1], matches[2]);
4391                }
4392            }else if (typeof styles == "object"){
4393                for (var style in styles){
4394                   el.setStyle(style, styles[style]);
4395                }
4396            }else if (typeof styles == "function"){
4397                 Roo.DomHelper.applyStyles(el, styles.call());
4398            }
4399         }
4400     },
4401
4402     /**
4403      * Inserts an HTML fragment into the Dom
4404      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4405      * @param {HTMLElement} el The context element
4406      * @param {String} html The HTML fragmenet
4407      * @return {HTMLElement} The new node
4408      */
4409     insertHtml : function(where, el, html){
4410         where = where.toLowerCase();
4411         if(el.insertAdjacentHTML){
4412             if(tableRe.test(el.tagName)){
4413                 var rs;
4414                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4415                     return rs;
4416                 }
4417             }
4418             switch(where){
4419                 case "beforebegin":
4420                     el.insertAdjacentHTML('BeforeBegin', html);
4421                     return el.previousSibling;
4422                 case "afterbegin":
4423                     el.insertAdjacentHTML('AfterBegin', html);
4424                     return el.firstChild;
4425                 case "beforeend":
4426                     el.insertAdjacentHTML('BeforeEnd', html);
4427                     return el.lastChild;
4428                 case "afterend":
4429                     el.insertAdjacentHTML('AfterEnd', html);
4430                     return el.nextSibling;
4431             }
4432             throw 'Illegal insertion point -> "' + where + '"';
4433         }
4434         var range = el.ownerDocument.createRange();
4435         var frag;
4436         switch(where){
4437              case "beforebegin":
4438                 range.setStartBefore(el);
4439                 frag = range.createContextualFragment(html);
4440                 el.parentNode.insertBefore(frag, el);
4441                 return el.previousSibling;
4442              case "afterbegin":
4443                 if(el.firstChild){
4444                     range.setStartBefore(el.firstChild);
4445                     frag = range.createContextualFragment(html);
4446                     el.insertBefore(frag, el.firstChild);
4447                     return el.firstChild;
4448                 }else{
4449                     el.innerHTML = html;
4450                     return el.firstChild;
4451                 }
4452             case "beforeend":
4453                 if(el.lastChild){
4454                     range.setStartAfter(el.lastChild);
4455                     frag = range.createContextualFragment(html);
4456                     el.appendChild(frag);
4457                     return el.lastChild;
4458                 }else{
4459                     el.innerHTML = html;
4460                     return el.lastChild;
4461                 }
4462             case "afterend":
4463                 range.setStartAfter(el);
4464                 frag = range.createContextualFragment(html);
4465                 el.parentNode.insertBefore(frag, el.nextSibling);
4466                 return el.nextSibling;
4467             }
4468             throw 'Illegal insertion point -> "' + where + '"';
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and inserts them before el
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     insertBefore : function(el, o, returnElement){
4479         return this.doInsert(el, o, returnElement, "beforeBegin");
4480     },
4481
4482     /**
4483      * Creates new Dom element(s) and inserts them after el
4484      * @param {String/HTMLElement/Element} el The context element
4485      * @param {Object} o The Dom object spec (and children)
4486      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4487      * @return {HTMLElement/Roo.Element} The new node
4488      */
4489     insertAfter : function(el, o, returnElement){
4490         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491     },
4492
4493     /**
4494      * Creates new Dom element(s) and inserts them as the first child of el
4495      * @param {String/HTMLElement/Element} el The context element
4496      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498      * @return {HTMLElement/Roo.Element} The new node
4499      */
4500     insertFirst : function(el, o, returnElement){
4501         return this.doInsert(el, o, returnElement, "afterBegin");
4502     },
4503
4504     // private
4505     doInsert : function(el, o, returnElement, pos, sibling){
4506         el = Roo.getDom(el);
4507         var newNode;
4508         if(this.useDom || o.ns){
4509             newNode = createDom(o, null);
4510             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4511         }else{
4512             var html = createHtml(o);
4513             newNode = this.insertHtml(pos, el, html);
4514         }
4515         return returnElement ? Roo.get(newNode, true) : newNode;
4516     },
4517
4518     /**
4519      * Creates new Dom element(s) and appends them to el
4520      * @param {String/HTMLElement/Element} el The context element
4521      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523      * @return {HTMLElement/Roo.Element} The new node
4524      */
4525     append : function(el, o, returnElement){
4526         el = Roo.getDom(el);
4527         var newNode;
4528         if(this.useDom || o.ns){
4529             newNode = createDom(o, null);
4530             el.appendChild(newNode);
4531         }else{
4532             var html = createHtml(o);
4533             newNode = this.insertHtml("beforeEnd", el, html);
4534         }
4535         return returnElement ? Roo.get(newNode, true) : newNode;
4536     },
4537
4538     /**
4539      * Creates new Dom element(s) and overwrites the contents of el with them
4540      * @param {String/HTMLElement/Element} el The context element
4541      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4542      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4543      * @return {HTMLElement/Roo.Element} The new node
4544      */
4545     overwrite : function(el, o, returnElement){
4546         el = Roo.getDom(el);
4547         if (o.ns) {
4548           
4549             while (el.childNodes.length) {
4550                 el.removeChild(el.firstChild);
4551             }
4552             createDom(o, el);
4553         } else {
4554             el.innerHTML = createHtml(o);   
4555         }
4556         
4557         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558     },
4559
4560     /**
4561      * Creates a new Roo.DomHelper.Template from the Dom object spec
4562      * @param {Object} o The Dom object spec (and children)
4563      * @return {Roo.DomHelper.Template} The new template
4564      */
4565     createTemplate : function(o){
4566         var html = createHtml(o);
4567         return new Roo.Template(html);
4568     }
4569     };
4570 }();
4571 /*
4572  * Based on:
4573  * Ext JS Library 1.1.1
4574  * Copyright(c) 2006-2007, Ext JS, LLC.
4575  *
4576  * Originally Released Under LGPL - original licence link has changed is not relivant.
4577  *
4578  * Fork - LGPL
4579  * <script type="text/javascript">
4580  */
4581  
4582 /**
4583 * @class Roo.Template
4584 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4585 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4586 * Usage:
4587 <pre><code>
4588 var t = new Roo.Template({
4589     html :  '&lt;div name="{id}"&gt;' + 
4590         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4591         '&lt;/div&gt;',
4592     myformat: function (value, allValues) {
4593         return 'XX' + value;
4594     }
4595 });
4596 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4597 </code></pre>
4598 * For more information see this blog post with examples:
4599 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4600      - Create Elements using DOM, HTML fragments and Templates</a>. 
4601 * @constructor
4602 * @param {Object} cfg - Configuration object.
4603 */
4604 Roo.Template = function(cfg){
4605     // BC!
4606     if(cfg instanceof Array){
4607         cfg = cfg.join("");
4608     }else if(arguments.length > 1){
4609         cfg = Array.prototype.join.call(arguments, "");
4610     }
4611     
4612     
4613     if (typeof(cfg) == 'object') {
4614         Roo.apply(this,cfg)
4615     } else {
4616         // bc
4617         this.html = cfg;
4618     }
4619     if (this.url) {
4620         this.load();
4621     }
4622     
4623 };
4624 Roo.Template.prototype = {
4625     
4626     /**
4627      * @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..
4628      *                    it should be fixed so that template is observable...
4629      */
4630     url : false,
4631     /**
4632      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633      */
4634     html : '',
4635     /**
4636      * Returns an HTML fragment of this template with the specified values applied.
4637      * @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'})
4638      * @return {String} The HTML fragment
4639      */
4640     applyTemplate : function(values){
4641         try {
4642            
4643             if(this.compiled){
4644                 return this.compiled(values);
4645             }
4646             var useF = this.disableFormats !== true;
4647             var fm = Roo.util.Format, tpl = this;
4648             var fn = function(m, name, format, args){
4649                 if(format && useF){
4650                     if(format.substr(0, 5) == "this."){
4651                         return tpl.call(format.substr(5), values[name], values);
4652                     }else{
4653                         if(args){
4654                             // quoted values are required for strings in compiled templates, 
4655                             // but for non compiled we need to strip them
4656                             // quoted reversed for jsmin
4657                             var re = /^\s*['"](.*)["']\s*$/;
4658                             args = args.split(',');
4659                             for(var i = 0, len = args.length; i < len; i++){
4660                                 args[i] = args[i].replace(re, "$1");
4661                             }
4662                             args = [values[name]].concat(args);
4663                         }else{
4664                             args = [values[name]];
4665                         }
4666                         return fm[format].apply(fm, args);
4667                     }
4668                 }else{
4669                     return values[name] !== undefined ? values[name] : "";
4670                 }
4671             };
4672             return this.html.replace(this.re, fn);
4673         } catch (e) {
4674             Roo.log(e);
4675             throw e;
4676         }
4677          
4678     },
4679     
4680     loading : false,
4681       
4682     load : function ()
4683     {
4684          
4685         if (this.loading) {
4686             return;
4687         }
4688         var _t = this;
4689         
4690         this.loading = true;
4691         this.compiled = false;
4692         
4693         var cx = new Roo.data.Connection();
4694         cx.request({
4695             url : this.url,
4696             method : 'GET',
4697             success : function (response) {
4698                 _t.loading = false;
4699                 _t.html = response.responseText;
4700                 _t.url = false;
4701                 _t.compile();
4702              },
4703             failure : function(response) {
4704                 Roo.log("Template failed to load from " + _t.url);
4705                 _t.loading = false;
4706             }
4707         });
4708     },
4709
4710     /**
4711      * Sets the HTML used as the template and optionally compiles it.
4712      * @param {String} html
4713      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4714      * @return {Roo.Template} this
4715      */
4716     set : function(html, compile){
4717         this.html = html;
4718         this.compiled = null;
4719         if(compile){
4720             this.compile();
4721         }
4722         return this;
4723     },
4724     
4725     /**
4726      * True to disable format functions (defaults to false)
4727      * @type Boolean
4728      */
4729     disableFormats : false,
4730     
4731     /**
4732     * The regular expression used to match template variables 
4733     * @type RegExp
4734     * @property 
4735     */
4736     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4737     
4738     /**
4739      * Compiles the template into an internal function, eliminating the RegEx overhead.
4740      * @return {Roo.Template} this
4741      */
4742     compile : function(){
4743         var fm = Roo.util.Format;
4744         var useF = this.disableFormats !== true;
4745         var sep = Roo.isGecko ? "+" : ",";
4746         var fn = function(m, name, format, args){
4747             if(format && useF){
4748                 args = args ? ',' + args : "";
4749                 if(format.substr(0, 5) != "this."){
4750                     format = "fm." + format + '(';
4751                 }else{
4752                     format = 'this.call("'+ format.substr(5) + '", ';
4753                     args = ", values";
4754                 }
4755             }else{
4756                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4757             }
4758             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4759         };
4760         var body;
4761         // branched to use + in gecko and [].join() in others
4762         if(Roo.isGecko){
4763             body = "this.compiled = function(values){ return '" +
4764                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4765                     "';};";
4766         }else{
4767             body = ["this.compiled = function(values){ return ['"];
4768             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4769             body.push("'].join('');};");
4770             body = body.join('');
4771         }
4772         /**
4773          * eval:var:values
4774          * eval:var:fm
4775          */
4776         eval(body);
4777         return this;
4778     },
4779     
4780     // private function used to call members
4781     call : function(fnName, value, allValues){
4782         return this[fnName](value, allValues);
4783     },
4784     
4785     /**
4786      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @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'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     insertFirst: function(el, values, returnElement){
4793         return this.doInsert('afterBegin', el, values, returnElement);
4794     },
4795
4796     /**
4797      * Applies the supplied values to the template and inserts the new node(s) before el.
4798      * @param {String/HTMLElement/Roo.Element} el The context element
4799      * @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'})
4800      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801      * @return {HTMLElement/Roo.Element} The new node or Element
4802      */
4803     insertBefore: function(el, values, returnElement){
4804         return this.doInsert('beforeBegin', el, values, returnElement);
4805     },
4806
4807     /**
4808      * Applies the supplied values to the template and inserts the new node(s) after el.
4809      * @param {String/HTMLElement/Roo.Element} el The context element
4810      * @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'})
4811      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4812      * @return {HTMLElement/Roo.Element} The new node or Element
4813      */
4814     insertAfter : function(el, values, returnElement){
4815         return this.doInsert('afterEnd', el, values, returnElement);
4816     },
4817     
4818     /**
4819      * Applies the supplied values to the template and appends the new node(s) to el.
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     append : function(el, values, returnElement){
4826         return this.doInsert('beforeEnd', el, values, returnElement);
4827     },
4828
4829     doInsert : function(where, el, values, returnEl){
4830         el = Roo.getDom(el);
4831         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4832         return returnEl ? Roo.get(newNode, true) : newNode;
4833     },
4834
4835     /**
4836      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4837      * @param {String/HTMLElement/Roo.Element} el The context element
4838      * @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'})
4839      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4840      * @return {HTMLElement/Roo.Element} The new node or Element
4841      */
4842     overwrite : function(el, values, returnElement){
4843         el = Roo.getDom(el);
4844         el.innerHTML = this.applyTemplate(values);
4845         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846     }
4847 };
4848 /**
4849  * Alias for {@link #applyTemplate}
4850  * @method
4851  */
4852 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4853
4854 // backwards compat
4855 Roo.DomHelper.Template = Roo.Template;
4856
4857 /**
4858  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4859  * @param {String/HTMLElement} el A DOM element or its id
4860  * @returns {Roo.Template} The created template
4861  * @static
4862  */
4863 Roo.Template.from = function(el){
4864     el = Roo.getDom(el);
4865     return new Roo.Template(el.value || el.innerHTML);
4866 };/*
4867  * Based on:
4868  * Ext JS Library 1.1.1
4869  * Copyright(c) 2006-2007, Ext JS, LLC.
4870  *
4871  * Originally Released Under LGPL - original licence link has changed is not relivant.
4872  *
4873  * Fork - LGPL
4874  * <script type="text/javascript">
4875  */
4876  
4877
4878 /*
4879  * This is code is also distributed under MIT license for use
4880  * with jQuery and prototype JavaScript libraries.
4881  */
4882 /**
4883  * @class Roo.DomQuery
4884 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).
4885 <p>
4886 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>
4887
4888 <p>
4889 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.
4890 </p>
4891 <h4>Element Selectors:</h4>
4892 <ul class="list">
4893     <li> <b>*</b> any element</li>
4894     <li> <b>E</b> an element with the tag E</li>
4895     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4896     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4897     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4898     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4899 </ul>
4900 <h4>Attribute Selectors:</h4>
4901 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4902 <ul class="list">
4903     <li> <b>E[foo]</b> has an attribute "foo"</li>
4904     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4905     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4906     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4907     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4908     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4909     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4910 </ul>
4911 <h4>Pseudo Classes:</h4>
4912 <ul class="list">
4913     <li> <b>E:first-child</b> E is the first child of its parent</li>
4914     <li> <b>E:last-child</b> E is the last child of its parent</li>
4915     <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>
4916     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4917     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4918     <li> <b>E:only-child</b> E is the only child of its parent</li>
4919     <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>
4920     <li> <b>E:first</b> the first E in the resultset</li>
4921     <li> <b>E:last</b> the last E in the resultset</li>
4922     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4923     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4924     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4925     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4926     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4927     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4928     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4929     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4930     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4931 </ul>
4932 <h4>CSS Value Selectors:</h4>
4933 <ul class="list">
4934     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4935     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4936     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4937     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4938     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4939     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 </ul>
4941  * @singleton
4942  */
4943 Roo.DomQuery = function(){
4944     var cache = {}, simpleCache = {}, valueCache = {};
4945     var nonSpace = /\S/;
4946     var trimRe = /^\s+|\s+$/g;
4947     var tplRe = /\{(\d+)\}/g;
4948     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4949     var tagTokenRe = /^(#)?([\w-\*]+)/;
4950     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4951
4952     function child(p, index){
4953         var i = 0;
4954         var n = p.firstChild;
4955         while(n){
4956             if(n.nodeType == 1){
4957                if(++i == index){
4958                    return n;
4959                }
4960             }
4961             n = n.nextSibling;
4962         }
4963         return null;
4964     };
4965
4966     function next(n){
4967         while((n = n.nextSibling) && n.nodeType != 1);
4968         return n;
4969     };
4970
4971     function prev(n){
4972         while((n = n.previousSibling) && n.nodeType != 1);
4973         return n;
4974     };
4975
4976     function children(d){
4977         var n = d.firstChild, ni = -1;
4978             while(n){
4979                 var nx = n.nextSibling;
4980                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4981                     d.removeChild(n);
4982                 }else{
4983                     n.nodeIndex = ++ni;
4984                 }
4985                 n = nx;
4986             }
4987             return this;
4988         };
4989
4990     function byClassName(c, a, v){
4991         if(!v){
4992             return c;
4993         }
4994         var r = [], ri = -1, cn;
4995         for(var i = 0, ci; ci = c[i]; i++){
4996             if((' '+ci.className+' ').indexOf(v) != -1){
4997                 r[++ri] = ci;
4998             }
4999         }
5000         return r;
5001     };
5002
5003     function attrValue(n, attr){
5004         if(!n.tagName && typeof n.length != "undefined"){
5005             n = n[0];
5006         }
5007         if(!n){
5008             return null;
5009         }
5010         if(attr == "for"){
5011             return n.htmlFor;
5012         }
5013         if(attr == "class" || attr == "className"){
5014             return n.className;
5015         }
5016         return n.getAttribute(attr) || n[attr];
5017
5018     };
5019
5020     function getNodes(ns, mode, tagName){
5021         var result = [], ri = -1, cs;
5022         if(!ns){
5023             return result;
5024         }
5025         tagName = tagName || "*";
5026         if(typeof ns.getElementsByTagName != "undefined"){
5027             ns = [ns];
5028         }
5029         if(!mode){
5030             for(var i = 0, ni; ni = ns[i]; i++){
5031                 cs = ni.getElementsByTagName(tagName);
5032                 for(var j = 0, ci; ci = cs[j]; j++){
5033                     result[++ri] = ci;
5034                 }
5035             }
5036         }else if(mode == "/" || mode == ">"){
5037             var utag = tagName.toUpperCase();
5038             for(var i = 0, ni, cn; ni = ns[i]; i++){
5039                 cn = ni.children || ni.childNodes;
5040                 for(var j = 0, cj; cj = cn[j]; j++){
5041                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5042                         result[++ri] = cj;
5043                     }
5044                 }
5045             }
5046         }else if(mode == "+"){
5047             var utag = tagName.toUpperCase();
5048             for(var i = 0, n; n = ns[i]; i++){
5049                 while((n = n.nextSibling) && n.nodeType != 1);
5050                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051                     result[++ri] = n;
5052                 }
5053             }
5054         }else if(mode == "~"){
5055             for(var i = 0, n; n = ns[i]; i++){
5056                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5057                 if(n){
5058                     result[++ri] = n;
5059                 }
5060             }
5061         }
5062         return result;
5063     };
5064
5065     function concat(a, b){
5066         if(b.slice){
5067             return a.concat(b);
5068         }
5069         for(var i = 0, l = b.length; i < l; i++){
5070             a[a.length] = b[i];
5071         }
5072         return a;
5073     }
5074
5075     function byTag(cs, tagName){
5076         if(cs.tagName || cs == document){
5077             cs = [cs];
5078         }
5079         if(!tagName){
5080             return cs;
5081         }
5082         var r = [], ri = -1;
5083         tagName = tagName.toLowerCase();
5084         for(var i = 0, ci; ci = cs[i]; i++){
5085             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5086                 r[++ri] = ci;
5087             }
5088         }
5089         return r;
5090     };
5091
5092     function byId(cs, attr, id){
5093         if(cs.tagName || cs == document){
5094             cs = [cs];
5095         }
5096         if(!id){
5097             return cs;
5098         }
5099         var r = [], ri = -1;
5100         for(var i = 0,ci; ci = cs[i]; i++){
5101             if(ci && ci.id == id){
5102                 r[++ri] = ci;
5103                 return r;
5104             }
5105         }
5106         return r;
5107     };
5108
5109     function byAttribute(cs, attr, value, op, custom){
5110         var r = [], ri = -1, st = custom=="{";
5111         var f = Roo.DomQuery.operators[op];
5112         for(var i = 0, ci; ci = cs[i]; i++){
5113             var a;
5114             if(st){
5115                 a = Roo.DomQuery.getStyle(ci, attr);
5116             }
5117             else if(attr == "class" || attr == "className"){
5118                 a = ci.className;
5119             }else if(attr == "for"){
5120                 a = ci.htmlFor;
5121             }else if(attr == "href"){
5122                 a = ci.getAttribute("href", 2);
5123             }else{
5124                 a = ci.getAttribute(attr);
5125             }
5126             if((f && f(a, value)) || (!f && a)){
5127                 r[++ri] = ci;
5128             }
5129         }
5130         return r;
5131     };
5132
5133     function byPseudo(cs, name, value){
5134         return Roo.DomQuery.pseudos[name](cs, value);
5135     };
5136
5137     // This is for IE MSXML which does not support expandos.
5138     // IE runs the same speed using setAttribute, however FF slows way down
5139     // and Safari completely fails so they need to continue to use expandos.
5140     var isIE = window.ActiveXObject ? true : false;
5141
5142     // this eval is stop the compressor from
5143     // renaming the variable to something shorter
5144     
5145     /** eval:var:batch */
5146     var batch = 30803; 
5147
5148     var key = 30803;
5149
5150     function nodupIEXml(cs){
5151         var d = ++key;
5152         cs[0].setAttribute("_nodup", d);
5153         var r = [cs[0]];
5154         for(var i = 1, len = cs.length; i < len; i++){
5155             var c = cs[i];
5156             if(!c.getAttribute("_nodup") != d){
5157                 c.setAttribute("_nodup", d);
5158                 r[r.length] = c;
5159             }
5160         }
5161         for(var i = 0, len = cs.length; i < len; i++){
5162             cs[i].removeAttribute("_nodup");
5163         }
5164         return r;
5165     }
5166
5167     function nodup(cs){
5168         if(!cs){
5169             return [];
5170         }
5171         var len = cs.length, c, i, r = cs, cj, ri = -1;
5172         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5173             return cs;
5174         }
5175         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5176             return nodupIEXml(cs);
5177         }
5178         var d = ++key;
5179         cs[0]._nodup = d;
5180         for(i = 1; c = cs[i]; i++){
5181             if(c._nodup != d){
5182                 c._nodup = d;
5183             }else{
5184                 r = [];
5185                 for(var j = 0; j < i; j++){
5186                     r[++ri] = cs[j];
5187                 }
5188                 for(j = i+1; cj = cs[j]; j++){
5189                     if(cj._nodup != d){
5190                         cj._nodup = d;
5191                         r[++ri] = cj;
5192                     }
5193                 }
5194                 return r;
5195             }
5196         }
5197         return r;
5198     }
5199
5200     function quickDiffIEXml(c1, c2){
5201         var d = ++key;
5202         for(var i = 0, len = c1.length; i < len; i++){
5203             c1[i].setAttribute("_qdiff", d);
5204         }
5205         var r = [];
5206         for(var i = 0, len = c2.length; i < len; i++){
5207             if(c2[i].getAttribute("_qdiff") != d){
5208                 r[r.length] = c2[i];
5209             }
5210         }
5211         for(var i = 0, len = c1.length; i < len; i++){
5212            c1[i].removeAttribute("_qdiff");
5213         }
5214         return r;
5215     }
5216
5217     function quickDiff(c1, c2){
5218         var len1 = c1.length;
5219         if(!len1){
5220             return c2;
5221         }
5222         if(isIE && c1[0].selectSingleNode){
5223             return quickDiffIEXml(c1, c2);
5224         }
5225         var d = ++key;
5226         for(var i = 0; i < len1; i++){
5227             c1[i]._qdiff = d;
5228         }
5229         var r = [];
5230         for(var i = 0, len = c2.length; i < len; i++){
5231             if(c2[i]._qdiff != d){
5232                 r[r.length] = c2[i];
5233             }
5234         }
5235         return r;
5236     }
5237
5238     function quickId(ns, mode, root, id){
5239         if(ns == root){
5240            var d = root.ownerDocument || root;
5241            return d.getElementById(id);
5242         }
5243         ns = getNodes(ns, mode, "*");
5244         return byId(ns, null, id);
5245     }
5246
5247     return {
5248         getStyle : function(el, name){
5249             return Roo.fly(el).getStyle(name);
5250         },
5251         /**
5252          * Compiles a selector/xpath query into a reusable function. The returned function
5253          * takes one parameter "root" (optional), which is the context node from where the query should start.
5254          * @param {String} selector The selector/xpath query
5255          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5256          * @return {Function}
5257          */
5258         compile : function(path, type){
5259             type = type || "select";
5260             
5261             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5262             var q = path, mode, lq;
5263             var tk = Roo.DomQuery.matchers;
5264             var tklen = tk.length;
5265             var mm;
5266
5267             // accept leading mode switch
5268             var lmode = q.match(modeRe);
5269             if(lmode && lmode[1]){
5270                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5271                 q = q.replace(lmode[1], "");
5272             }
5273             // strip leading slashes
5274             while(path.substr(0, 1)=="/"){
5275                 path = path.substr(1);
5276             }
5277
5278             while(q && lq != q){
5279                 lq = q;
5280                 var tm = q.match(tagTokenRe);
5281                 if(type == "select"){
5282                     if(tm){
5283                         if(tm[1] == "#"){
5284                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5285                         }else{
5286                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5287                         }
5288                         q = q.replace(tm[0], "");
5289                     }else if(q.substr(0, 1) != '@'){
5290                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5291                     }
5292                 }else{
5293                     if(tm){
5294                         if(tm[1] == "#"){
5295                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5296                         }else{
5297                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5298                         }
5299                         q = q.replace(tm[0], "");
5300                     }
5301                 }
5302                 while(!(mm = q.match(modeRe))){
5303                     var matched = false;
5304                     for(var j = 0; j < tklen; j++){
5305                         var t = tk[j];
5306                         var m = q.match(t.re);
5307                         if(m){
5308                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5309                                                     return m[i];
5310                                                 });
5311                             q = q.replace(m[0], "");
5312                             matched = true;
5313                             break;
5314                         }
5315                     }
5316                     // prevent infinite loop on bad selector
5317                     if(!matched){
5318                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5319                     }
5320                 }
5321                 if(mm[1]){
5322                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5323                     q = q.replace(mm[1], "");
5324                 }
5325             }
5326             fn[fn.length] = "return nodup(n);\n}";
5327             
5328              /** 
5329               * list of variables that need from compression as they are used by eval.
5330              *  eval:var:batch 
5331              *  eval:var:nodup
5332              *  eval:var:byTag
5333              *  eval:var:ById
5334              *  eval:var:getNodes
5335              *  eval:var:quickId
5336              *  eval:var:mode
5337              *  eval:var:root
5338              *  eval:var:n
5339              *  eval:var:byClassName
5340              *  eval:var:byPseudo
5341              *  eval:var:byAttribute
5342              *  eval:var:attrValue
5343              * 
5344              **/ 
5345             eval(fn.join(""));
5346             return f;
5347         },
5348
5349         /**
5350          * Selects a group of elements.
5351          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Array}
5354          */
5355         select : function(path, root, type){
5356             if(!root || root == document){
5357                 root = document;
5358             }
5359             if(typeof root == "string"){
5360                 root = document.getElementById(root);
5361             }
5362             var paths = path.split(",");
5363             var results = [];
5364             for(var i = 0, len = paths.length; i < len; i++){
5365                 var p = paths[i].replace(trimRe, "");
5366                 if(!cache[p]){
5367                     cache[p] = Roo.DomQuery.compile(p);
5368                     if(!cache[p]){
5369                         throw p + " is not a valid selector";
5370                     }
5371                 }
5372                 var result = cache[p](root);
5373                 if(result && result != document){
5374                     results = results.concat(result);
5375                 }
5376             }
5377             if(paths.length > 1){
5378                 return nodup(results);
5379             }
5380             return results;
5381         },
5382
5383         /**
5384          * Selects a single element.
5385          * @param {String} selector The selector/xpath query
5386          * @param {Node} root (optional) The start of the query (defaults to document).
5387          * @return {Element}
5388          */
5389         selectNode : function(path, root){
5390             return Roo.DomQuery.select(path, root)[0];
5391         },
5392
5393         /**
5394          * Selects the value of a node, optionally replacing null with the defaultValue.
5395          * @param {String} selector The selector/xpath query
5396          * @param {Node} root (optional) The start of the query (defaults to document).
5397          * @param {String} defaultValue
5398          */
5399         selectValue : function(path, root, defaultValue){
5400             path = path.replace(trimRe, "");
5401             if(!valueCache[path]){
5402                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5403             }
5404             var n = valueCache[path](root);
5405             n = n[0] ? n[0] : n;
5406             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5407             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408         },
5409
5410         /**
5411          * Selects the value of a node, parsing integers and floats.
5412          * @param {String} selector The selector/xpath query
5413          * @param {Node} root (optional) The start of the query (defaults to document).
5414          * @param {Number} defaultValue
5415          * @return {Number}
5416          */
5417         selectNumber : function(path, root, defaultValue){
5418             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5419             return parseFloat(v);
5420         },
5421
5422         /**
5423          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5424          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5425          * @param {String} selector The simple selector to test
5426          * @return {Boolean}
5427          */
5428         is : function(el, ss){
5429             if(typeof el == "string"){
5430                 el = document.getElementById(el);
5431             }
5432             var isArray = (el instanceof Array);
5433             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5434             return isArray ? (result.length == el.length) : (result.length > 0);
5435         },
5436
5437         /**
5438          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5439          * @param {Array} el An array of elements to filter
5440          * @param {String} selector The simple selector to test
5441          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5442          * the selector instead of the ones that match
5443          * @return {Array}
5444          */
5445         filter : function(els, ss, nonMatches){
5446             ss = ss.replace(trimRe, "");
5447             if(!simpleCache[ss]){
5448                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5449             }
5450             var result = simpleCache[ss](els);
5451             return nonMatches ? quickDiff(result, els) : result;
5452         },
5453
5454         /**
5455          * Collection of matching regular expressions and code snippets.
5456          */
5457         matchers : [{
5458                 re: /^\.([\w-]+)/,
5459                 select: 'n = byClassName(n, null, " {1} ");'
5460             }, {
5461                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5462                 select: 'n = byPseudo(n, "{1}", "{2}");'
5463             },{
5464                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5465                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5466             }, {
5467                 re: /^#([\w-]+)/,
5468                 select: 'n = byId(n, null, "{1}");'
5469             },{
5470                 re: /^@([\w-]+)/,
5471                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5472             }
5473         ],
5474
5475         /**
5476          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5477          * 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;.
5478          */
5479         operators : {
5480             "=" : function(a, v){
5481                 return a == v;
5482             },
5483             "!=" : function(a, v){
5484                 return a != v;
5485             },
5486             "^=" : function(a, v){
5487                 return a && a.substr(0, v.length) == v;
5488             },
5489             "$=" : function(a, v){
5490                 return a && a.substr(a.length-v.length) == v;
5491             },
5492             "*=" : function(a, v){
5493                 return a && a.indexOf(v) !== -1;
5494             },
5495             "%=" : function(a, v){
5496                 return (a % v) == 0;
5497             },
5498             "|=" : function(a, v){
5499                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5500             },
5501             "~=" : function(a, v){
5502                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5503             }
5504         },
5505
5506         /**
5507          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5508          * and the argument (if any) supplied in the selector.
5509          */
5510         pseudos : {
5511             "first-child" : function(c){
5512                 var r = [], ri = -1, n;
5513                 for(var i = 0, ci; ci = n = c[i]; i++){
5514                     while((n = n.previousSibling) && n.nodeType != 1);
5515                     if(!n){
5516                         r[++ri] = ci;
5517                     }
5518                 }
5519                 return r;
5520             },
5521
5522             "last-child" : function(c){
5523                 var r = [], ri = -1, n;
5524                 for(var i = 0, ci; ci = n = c[i]; i++){
5525                     while((n = n.nextSibling) && n.nodeType != 1);
5526                     if(!n){
5527                         r[++ri] = ci;
5528                     }
5529                 }
5530                 return r;
5531             },
5532
5533             "nth-child" : function(c, a) {
5534                 var r = [], ri = -1;
5535                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5536                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5537                 for(var i = 0, n; n = c[i]; i++){
5538                     var pn = n.parentNode;
5539                     if (batch != pn._batch) {
5540                         var j = 0;
5541                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5542                             if(cn.nodeType == 1){
5543                                cn.nodeIndex = ++j;
5544                             }
5545                         }
5546                         pn._batch = batch;
5547                     }
5548                     if (f == 1) {
5549                         if (l == 0 || n.nodeIndex == l){
5550                             r[++ri] = n;
5551                         }
5552                     } else if ((n.nodeIndex + l) % f == 0){
5553                         r[++ri] = n;
5554                     }
5555                 }
5556
5557                 return r;
5558             },
5559
5560             "only-child" : function(c){
5561                 var r = [], ri = -1;;
5562                 for(var i = 0, ci; ci = c[i]; i++){
5563                     if(!prev(ci) && !next(ci)){
5564                         r[++ri] = ci;
5565                     }
5566                 }
5567                 return r;
5568             },
5569
5570             "empty" : function(c){
5571                 var r = [], ri = -1;
5572                 for(var i = 0, ci; ci = c[i]; i++){
5573                     var cns = ci.childNodes, j = 0, cn, empty = true;
5574                     while(cn = cns[j]){
5575                         ++j;
5576                         if(cn.nodeType == 1 || cn.nodeType == 3){
5577                             empty = false;
5578                             break;
5579                         }
5580                     }
5581                     if(empty){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "contains" : function(c, v){
5589                 var r = [], ri = -1;
5590                 for(var i = 0, ci; ci = c[i]; i++){
5591                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5592                         r[++ri] = ci;
5593                     }
5594                 }
5595                 return r;
5596             },
5597
5598             "nodeValue" : function(c, v){
5599                 var r = [], ri = -1;
5600                 for(var i = 0, ci; ci = c[i]; i++){
5601                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5602                         r[++ri] = ci;
5603                     }
5604                 }
5605                 return r;
5606             },
5607
5608             "checked" : function(c){
5609                 var r = [], ri = -1;
5610                 for(var i = 0, ci; ci = c[i]; i++){
5611                     if(ci.checked == true){
5612                         r[++ri] = ci;
5613                     }
5614                 }
5615                 return r;
5616             },
5617
5618             "not" : function(c, ss){
5619                 return Roo.DomQuery.filter(c, ss, true);
5620             },
5621
5622             "odd" : function(c){
5623                 return this["nth-child"](c, "odd");
5624             },
5625
5626             "even" : function(c){
5627                 return this["nth-child"](c, "even");
5628             },
5629
5630             "nth" : function(c, a){
5631                 return c[a-1] || [];
5632             },
5633
5634             "first" : function(c){
5635                 return c[0] || [];
5636             },
5637
5638             "last" : function(c){
5639                 return c[c.length-1] || [];
5640             },
5641
5642             "has" : function(c, ss){
5643                 var s = Roo.DomQuery.select;
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     if(s(ss, ci).length > 0){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             },
5652
5653             "next" : function(c, ss){
5654                 var is = Roo.DomQuery.is;
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     var n = next(ci);
5658                     if(n && is(n, ss)){
5659                         r[++ri] = ci;
5660                     }
5661                 }
5662                 return r;
5663             },
5664
5665             "prev" : function(c, ss){
5666                 var is = Roo.DomQuery.is;
5667                 var r = [], ri = -1;
5668                 for(var i = 0, ci; ci = c[i]; i++){
5669                     var n = prev(ci);
5670                     if(n && is(n, ss)){
5671                         r[++ri] = ci;
5672                     }
5673                 }
5674                 return r;
5675             }
5676         }
5677     };
5678 }();
5679
5680 /**
5681  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5682  * @param {String} path The selector/xpath query
5683  * @param {Node} root (optional) The start of the query (defaults to document).
5684  * @return {Array}
5685  * @member Roo
5686  * @method query
5687  */
5688 Roo.query = Roo.DomQuery.select;
5689 /*
5690  * Based on:
5691  * Ext JS Library 1.1.1
5692  * Copyright(c) 2006-2007, Ext JS, LLC.
5693  *
5694  * Originally Released Under LGPL - original licence link has changed is not relivant.
5695  *
5696  * Fork - LGPL
5697  * <script type="text/javascript">
5698  */
5699
5700 /**
5701  * @class Roo.util.Observable
5702  * Base class that provides a common interface for publishing events. Subclasses are expected to
5703  * to have a property "events" with all the events defined.<br>
5704  * For example:
5705  * <pre><code>
5706  Employee = function(name){
5707     this.name = name;
5708     this.addEvents({
5709         "fired" : true,
5710         "quit" : true
5711     });
5712  }
5713  Roo.extend(Employee, Roo.util.Observable);
5714 </code></pre>
5715  * @param {Object} config properties to use (incuding events / listeners)
5716  */
5717
5718 Roo.util.Observable = function(cfg){
5719     
5720     cfg = cfg|| {};
5721     this.addEvents(cfg.events || {});
5722     if (cfg.events) {
5723         delete cfg.events; // make sure
5724     }
5725      
5726     Roo.apply(this, cfg);
5727     
5728     if(this.listeners){
5729         this.on(this.listeners);
5730         delete this.listeners;
5731     }
5732 };
5733 Roo.util.Observable.prototype = {
5734     /** 
5735  * @cfg {Object} listeners  list of events and functions to call for this object, 
5736  * For example :
5737  * <pre><code>
5738     listeners :  { 
5739        'click' : function(e) {
5740            ..... 
5741         } ,
5742         .... 
5743     } 
5744   </code></pre>
5745  */
5746     
5747     
5748     /**
5749      * Fires the specified event with the passed parameters (minus the event name).
5750      * @param {String} eventName
5751      * @param {Object...} args Variable number of parameters are passed to handlers
5752      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5753      */
5754     fireEvent : function(){
5755         var ce = this.events[arguments[0].toLowerCase()];
5756         if(typeof ce == "object"){
5757             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5758         }else{
5759             return true;
5760         }
5761     },
5762
5763     // private
5764     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5765
5766     /**
5767      * Appends an event handler to this component
5768      * @param {String}   eventName The type of event to listen for
5769      * @param {Function} handler The method the event invokes
5770      * @param {Object}   scope (optional) The scope in which to execute the handler
5771      * function. The handler function's "this" context.
5772      * @param {Object}   options (optional) An object containing handler configuration
5773      * properties. This may contain any of the following properties:<ul>
5774      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5775      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5776      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5777      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5778      * by the specified number of milliseconds. If the event fires again within that time, the original
5779      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5780      * </ul><br>
5781      * <p>
5782      * <b>Combining Options</b><br>
5783      * Using the options argument, it is possible to combine different types of listeners:<br>
5784      * <br>
5785      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5786                 <pre><code>
5787                 el.on('click', this.onClick, this, {
5788                         single: true,
5789                 delay: 100,
5790                 forumId: 4
5791                 });
5792                 </code></pre>
5793      * <p>
5794      * <b>Attaching multiple handlers in 1 call</b><br>
5795      * The method also allows for a single argument to be passed which is a config object containing properties
5796      * which specify multiple handlers.
5797      * <pre><code>
5798                 el.on({
5799                         'click': {
5800                         fn: this.onClick,
5801                         scope: this,
5802                         delay: 100
5803                 }, 
5804                 'mouseover': {
5805                         fn: this.onMouseOver,
5806                         scope: this
5807                 },
5808                 'mouseout': {
5809                         fn: this.onMouseOut,
5810                         scope: this
5811                 }
5812                 });
5813                 </code></pre>
5814      * <p>
5815      * Or a shorthand syntax which passes the same scope object to all handlers:
5816         <pre><code>
5817                 el.on({
5818                         'click': this.onClick,
5819                 'mouseover': this.onMouseOver,
5820                 'mouseout': this.onMouseOut,
5821                 scope: this
5822                 });
5823                 </code></pre>
5824      */
5825     addListener : function(eventName, fn, scope, o){
5826         if(typeof eventName == "object"){
5827             o = eventName;
5828             for(var e in o){
5829                 if(this.filterOptRe.test(e)){
5830                     continue;
5831                 }
5832                 if(typeof o[e] == "function"){
5833                     // shared options
5834                     this.addListener(e, o[e], o.scope,  o);
5835                 }else{
5836                     // individual options
5837                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5838                 }
5839             }
5840             return;
5841         }
5842         o = (!o || typeof o == "boolean") ? {} : o;
5843         eventName = eventName.toLowerCase();
5844         var ce = this.events[eventName] || true;
5845         if(typeof ce == "boolean"){
5846             ce = new Roo.util.Event(this, eventName);
5847             this.events[eventName] = ce;
5848         }
5849         ce.addListener(fn, scope, o);
5850     },
5851
5852     /**
5853      * Removes a listener
5854      * @param {String}   eventName     The type of event to listen for
5855      * @param {Function} handler        The handler to remove
5856      * @param {Object}   scope  (optional) The scope (this object) for the handler
5857      */
5858     removeListener : function(eventName, fn, scope){
5859         var ce = this.events[eventName.toLowerCase()];
5860         if(typeof ce == "object"){
5861             ce.removeListener(fn, scope);
5862         }
5863     },
5864
5865     /**
5866      * Removes all listeners for this object
5867      */
5868     purgeListeners : function(){
5869         for(var evt in this.events){
5870             if(typeof this.events[evt] == "object"){
5871                  this.events[evt].clearListeners();
5872             }
5873         }
5874     },
5875
5876     relayEvents : function(o, events){
5877         var createHandler = function(ename){
5878             return function(){
5879                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5880             };
5881         };
5882         for(var i = 0, len = events.length; i < len; i++){
5883             var ename = events[i];
5884             if(!this.events[ename]){ this.events[ename] = true; };
5885             o.on(ename, createHandler(ename), this);
5886         }
5887     },
5888
5889     /**
5890      * Used to define events on this Observable
5891      * @param {Object} object The object with the events defined
5892      */
5893     addEvents : function(o){
5894         if(!this.events){
5895             this.events = {};
5896         }
5897         Roo.applyIf(this.events, o);
5898     },
5899
5900     /**
5901      * Checks to see if this object has any listeners for a specified event
5902      * @param {String} eventName The name of the event to check for
5903      * @return {Boolean} True if the event is being listened for, else false
5904      */
5905     hasListener : function(eventName){
5906         var e = this.events[eventName];
5907         return typeof e == "object" && e.listeners.length > 0;
5908     }
5909 };
5910 /**
5911  * Appends an event handler to this element (shorthand for addListener)
5912  * @param {String}   eventName     The type of event to listen for
5913  * @param {Function} handler        The method the event invokes
5914  * @param {Object}   scope (optional) The scope in which to execute the handler
5915  * function. The handler function's "this" context.
5916  * @param {Object}   options  (optional)
5917  * @method
5918  */
5919 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5920 /**
5921  * Removes a listener (shorthand for removeListener)
5922  * @param {String}   eventName     The type of event to listen for
5923  * @param {Function} handler        The handler to remove
5924  * @param {Object}   scope  (optional) The scope (this object) for the handler
5925  * @method
5926  */
5927 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5928
5929 /**
5930  * Starts capture on the specified Observable. All events will be passed
5931  * to the supplied function with the event name + standard signature of the event
5932  * <b>before</b> the event is fired. If the supplied function returns false,
5933  * the event will not fire.
5934  * @param {Observable} o The Observable to capture
5935  * @param {Function} fn The function to call
5936  * @param {Object} scope (optional) The scope (this object) for the fn
5937  * @static
5938  */
5939 Roo.util.Observable.capture = function(o, fn, scope){
5940     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 };
5942
5943 /**
5944  * Removes <b>all</b> added captures from the Observable.
5945  * @param {Observable} o The Observable to release
5946  * @static
5947  */
5948 Roo.util.Observable.releaseCapture = function(o){
5949     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5950 };
5951
5952 (function(){
5953
5954     var createBuffered = function(h, o, scope){
5955         var task = new Roo.util.DelayedTask();
5956         return function(){
5957             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958         };
5959     };
5960
5961     var createSingle = function(h, e, fn, scope){
5962         return function(){
5963             e.removeListener(fn, scope);
5964             return h.apply(scope, arguments);
5965         };
5966     };
5967
5968     var createDelayed = function(h, o, scope){
5969         return function(){
5970             var args = Array.prototype.slice.call(arguments, 0);
5971             setTimeout(function(){
5972                 h.apply(scope, args);
5973             }, o.delay || 10);
5974         };
5975     };
5976
5977     Roo.util.Event = function(obj, name){
5978         this.name = name;
5979         this.obj = obj;
5980         this.listeners = [];
5981     };
5982
5983     Roo.util.Event.prototype = {
5984         addListener : function(fn, scope, options){
5985             var o = options || {};
5986             scope = scope || this.obj;
5987             if(!this.isListening(fn, scope)){
5988                 var l = {fn: fn, scope: scope, options: o};
5989                 var h = fn;
5990                 if(o.delay){
5991                     h = createDelayed(h, o, scope);
5992                 }
5993                 if(o.single){
5994                     h = createSingle(h, this, fn, scope);
5995                 }
5996                 if(o.buffer){
5997                     h = createBuffered(h, o, scope);
5998                 }
5999                 l.fireFn = h;
6000                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6001                     this.listeners.push(l);
6002                 }else{
6003                     this.listeners = this.listeners.slice(0);
6004                     this.listeners.push(l);
6005                 }
6006             }
6007         },
6008
6009         findListener : function(fn, scope){
6010             scope = scope || this.obj;
6011             var ls = this.listeners;
6012             for(var i = 0, len = ls.length; i < len; i++){
6013                 var l = ls[i];
6014                 if(l.fn == fn && l.scope == scope){
6015                     return i;
6016                 }
6017             }
6018             return -1;
6019         },
6020
6021         isListening : function(fn, scope){
6022             return this.findListener(fn, scope) != -1;
6023         },
6024
6025         removeListener : function(fn, scope){
6026             var index;
6027             if((index = this.findListener(fn, scope)) != -1){
6028                 if(!this.firing){
6029                     this.listeners.splice(index, 1);
6030                 }else{
6031                     this.listeners = this.listeners.slice(0);
6032                     this.listeners.splice(index, 1);
6033                 }
6034                 return true;
6035             }
6036             return false;
6037         },
6038
6039         clearListeners : function(){
6040             this.listeners = [];
6041         },
6042
6043         fire : function(){
6044             var ls = this.listeners, scope, len = ls.length;
6045             if(len > 0){
6046                 this.firing = true;
6047                 var args = Array.prototype.slice.call(arguments, 0);
6048                 for(var i = 0; i < len; i++){
6049                     var l = ls[i];
6050                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6051                         this.firing = false;
6052                         return false;
6053                     }
6054                 }
6055                 this.firing = false;
6056             }
6057             return true;
6058         }
6059     };
6060 })();/*
6061  * RooJS Library 
6062  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6063  *
6064  * Licence LGPL 
6065  *
6066  */
6067  
6068 /**
6069  * @class Roo.Document
6070  * @extends Roo.util.Observable
6071  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6072  * 
6073  * @param {Object} config the methods and properties of the 'base' class for the application.
6074  * 
6075  *  Generic Page handler - implement this to start your app..
6076  * 
6077  * eg.
6078  *  MyProject = new Roo.Document({
6079         events : {
6080             'load' : true // your events..
6081         },
6082         listeners : {
6083             'ready' : function() {
6084                 // fired on Roo.onReady()
6085             }
6086         }
6087  * 
6088  */
6089 Roo.Document = function(cfg) {
6090      
6091     this.addEvents({ 
6092         'ready' : true
6093     });
6094     Roo.util.Observable.call(this,cfg);
6095     
6096     var _this = this;
6097     
6098     Roo.onReady(function() {
6099         _this.fireEvent('ready');
6100     },null,false);
6101     
6102     
6103 }
6104
6105 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6106  * Based on:
6107  * Ext JS Library 1.1.1
6108  * Copyright(c) 2006-2007, Ext JS, LLC.
6109  *
6110  * Originally Released Under LGPL - original licence link has changed is not relivant.
6111  *
6112  * Fork - LGPL
6113  * <script type="text/javascript">
6114  */
6115
6116 /**
6117  * @class Roo.EventManager
6118  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6119  * several useful events directly.
6120  * See {@link Roo.EventObject} for more details on normalized event objects.
6121  * @singleton
6122  */
6123 Roo.EventManager = function(){
6124     var docReadyEvent, docReadyProcId, docReadyState = false;
6125     var resizeEvent, resizeTask, textEvent, textSize;
6126     var E = Roo.lib.Event;
6127     var D = Roo.lib.Dom;
6128
6129     
6130     
6131
6132     var fireDocReady = function(){
6133         if(!docReadyState){
6134             docReadyState = true;
6135             Roo.isReady = true;
6136             if(docReadyProcId){
6137                 clearInterval(docReadyProcId);
6138             }
6139             if(Roo.isGecko || Roo.isOpera) {
6140                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6141             }
6142             if(Roo.isIE){
6143                 var defer = document.getElementById("ie-deferred-loader");
6144                 if(defer){
6145                     defer.onreadystatechange = null;
6146                     defer.parentNode.removeChild(defer);
6147                 }
6148             }
6149             if(docReadyEvent){
6150                 docReadyEvent.fire();
6151                 docReadyEvent.clearListeners();
6152             }
6153         }
6154     };
6155     
6156     var initDocReady = function(){
6157         docReadyEvent = new Roo.util.Event();
6158         if(Roo.isGecko || Roo.isOpera) {
6159             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6160         }else if(Roo.isIE){
6161             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6162             var defer = document.getElementById("ie-deferred-loader");
6163             defer.onreadystatechange = function(){
6164                 if(this.readyState == "complete"){
6165                     fireDocReady();
6166                 }
6167             };
6168         }else if(Roo.isSafari){ 
6169             docReadyProcId = setInterval(function(){
6170                 var rs = document.readyState;
6171                 if(rs == "complete") {
6172                     fireDocReady();     
6173                  }
6174             }, 10);
6175         }
6176         // no matter what, make sure it fires on load
6177         E.on(window, "load", fireDocReady);
6178     };
6179
6180     var createBuffered = function(h, o){
6181         var task = new Roo.util.DelayedTask(h);
6182         return function(e){
6183             // create new event object impl so new events don't wipe out properties
6184             e = new Roo.EventObjectImpl(e);
6185             task.delay(o.buffer, h, null, [e]);
6186         };
6187     };
6188
6189     var createSingle = function(h, el, ename, fn){
6190         return function(e){
6191             Roo.EventManager.removeListener(el, ename, fn);
6192             h(e);
6193         };
6194     };
6195
6196     var createDelayed = function(h, o){
6197         return function(e){
6198             // create new event object impl so new events don't wipe out properties
6199             e = new Roo.EventObjectImpl(e);
6200             setTimeout(function(){
6201                 h(e);
6202             }, o.delay || 10);
6203         };
6204     };
6205     var transitionEndVal = false;
6206     
6207     var transitionEnd = function()
6208     {
6209         if (transitionEndVal) {
6210             return transitionEndVal;
6211         }
6212         var el = document.createElement('div');
6213
6214         var transEndEventNames = {
6215             WebkitTransition : 'webkitTransitionEnd',
6216             MozTransition    : 'transitionend',
6217             OTransition      : 'oTransitionEnd otransitionend',
6218             transition       : 'transitionend'
6219         };
6220     
6221         for (var name in transEndEventNames) {
6222             if (el.style[name] !== undefined) {
6223                 transitionEndVal = transEndEventNames[name];
6224                 return  transitionEndVal ;
6225             }
6226         }
6227     }
6228     
6229
6230     var listen = function(element, ename, opt, fn, scope){
6231         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6232         fn = fn || o.fn; scope = scope || o.scope;
6233         var el = Roo.getDom(element);
6234         
6235         
6236         if(!el){
6237             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6238         }
6239         
6240         if (ename == 'transitionend') {
6241             ename = transitionEnd();
6242         }
6243         var h = function(e){
6244             e = Roo.EventObject.setEvent(e);
6245             var t;
6246             if(o.delegate){
6247                 t = e.getTarget(o.delegate, el);
6248                 if(!t){
6249                     return;
6250                 }
6251             }else{
6252                 t = e.target;
6253             }
6254             if(o.stopEvent === true){
6255                 e.stopEvent();
6256             }
6257             if(o.preventDefault === true){
6258                e.preventDefault();
6259             }
6260             if(o.stopPropagation === true){
6261                 e.stopPropagation();
6262             }
6263
6264             if(o.normalized === false){
6265                 e = e.browserEvent;
6266             }
6267
6268             fn.call(scope || el, e, t, o);
6269         };
6270         if(o.delay){
6271             h = createDelayed(h, o);
6272         }
6273         if(o.single){
6274             h = createSingle(h, el, ename, fn);
6275         }
6276         if(o.buffer){
6277             h = createBuffered(h, o);
6278         }
6279         fn._handlers = fn._handlers || [];
6280         
6281         
6282         fn._handlers.push([Roo.id(el), ename, h]);
6283         
6284         
6285          
6286         E.on(el, ename, h);
6287         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6288             el.addEventListener("DOMMouseScroll", h, false);
6289             E.on(window, 'unload', function(){
6290                 el.removeEventListener("DOMMouseScroll", h, false);
6291             });
6292         }
6293         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6294             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6295         }
6296         return h;
6297     };
6298
6299     var stopListening = function(el, ename, fn){
6300         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6301         if(hds){
6302             for(var i = 0, len = hds.length; i < len; i++){
6303                 var h = hds[i];
6304                 if(h[0] == id && h[1] == ename){
6305                     hd = h[2];
6306                     hds.splice(i, 1);
6307                     break;
6308                 }
6309             }
6310         }
6311         E.un(el, ename, hd);
6312         el = Roo.getDom(el);
6313         if(ename == "mousewheel" && el.addEventListener){
6314             el.removeEventListener("DOMMouseScroll", hd, false);
6315         }
6316         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6317             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318         }
6319     };
6320
6321     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6322     
6323     var pub = {
6324         
6325         
6326         /** 
6327          * Fix for doc tools
6328          * @scope Roo.EventManager
6329          */
6330         
6331         
6332         /** 
6333          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6334          * object with a Roo.EventObject
6335          * @param {Function} fn        The method the event invokes
6336          * @param {Object}   scope    An object that becomes the scope of the handler
6337          * @param {boolean}  override If true, the obj passed in becomes
6338          *                             the execution scope of the listener
6339          * @return {Function} The wrapped function
6340          * @deprecated
6341          */
6342         wrap : function(fn, scope, override){
6343             return function(e){
6344                 Roo.EventObject.setEvent(e);
6345                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6346             };
6347         },
6348         
6349         /**
6350      * Appends an event handler to an element (shorthand for addListener)
6351      * @param {String/HTMLElement}   element        The html element or id to assign the
6352      * @param {String}   eventName The type of event to listen for
6353      * @param {Function} handler The method the event invokes
6354      * @param {Object}   scope (optional) The scope in which to execute the handler
6355      * function. The handler function's "this" context.
6356      * @param {Object}   options (optional) An object containing handler configuration
6357      * properties. This may contain any of the following properties:<ul>
6358      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6359      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6360      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6361      * <li>preventDefault {Boolean} True to prevent the default action</li>
6362      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6363      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6364      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6365      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6366      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6367      * by the specified number of milliseconds. If the event fires again within that time, the original
6368      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6369      * </ul><br>
6370      * <p>
6371      * <b>Combining Options</b><br>
6372      * Using the options argument, it is possible to combine different types of listeners:<br>
6373      * <br>
6374      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6375      * Code:<pre><code>
6376 el.on('click', this.onClick, this, {
6377     single: true,
6378     delay: 100,
6379     stopEvent : true,
6380     forumId: 4
6381 });</code></pre>
6382      * <p>
6383      * <b>Attaching multiple handlers in 1 call</b><br>
6384       * The method also allows for a single argument to be passed which is a config object containing properties
6385      * which specify multiple handlers.
6386      * <p>
6387      * Code:<pre><code>
6388 el.on({
6389     'click' : {
6390         fn: this.onClick
6391         scope: this,
6392         delay: 100
6393     },
6394     'mouseover' : {
6395         fn: this.onMouseOver
6396         scope: this
6397     },
6398     'mouseout' : {
6399         fn: this.onMouseOut
6400         scope: this
6401     }
6402 });</code></pre>
6403      * <p>
6404      * Or a shorthand syntax:<br>
6405      * Code:<pre><code>
6406 el.on({
6407     'click' : this.onClick,
6408     'mouseover' : this.onMouseOver,
6409     'mouseout' : this.onMouseOut
6410     scope: this
6411 });</code></pre>
6412      */
6413         addListener : function(element, eventName, fn, scope, options){
6414             if(typeof eventName == "object"){
6415                 var o = eventName;
6416                 for(var e in o){
6417                     if(propRe.test(e)){
6418                         continue;
6419                     }
6420                     if(typeof o[e] == "function"){
6421                         // shared options
6422                         listen(element, e, o, o[e], o.scope);
6423                     }else{
6424                         // individual options
6425                         listen(element, e, o[e]);
6426                     }
6427                 }
6428                 return;
6429             }
6430             return listen(element, eventName, options, fn, scope);
6431         },
6432         
6433         /**
6434          * Removes an event handler
6435          *
6436          * @param {String/HTMLElement}   element        The id or html element to remove the 
6437          *                             event from
6438          * @param {String}   eventName     The type of event
6439          * @param {Function} fn
6440          * @return {Boolean} True if a listener was actually removed
6441          */
6442         removeListener : function(element, eventName, fn){
6443             return stopListening(element, eventName, fn);
6444         },
6445         
6446         /**
6447          * Fires when the document is ready (before onload and before images are loaded). Can be 
6448          * accessed shorthanded Roo.onReady().
6449          * @param {Function} fn        The method the event invokes
6450          * @param {Object}   scope    An  object that becomes the scope of the handler
6451          * @param {boolean}  options
6452          */
6453         onDocumentReady : function(fn, scope, options){
6454             if(docReadyState){ // if it already fired
6455                 docReadyEvent.addListener(fn, scope, options);
6456                 docReadyEvent.fire();
6457                 docReadyEvent.clearListeners();
6458                 return;
6459             }
6460             if(!docReadyEvent){
6461                 initDocReady();
6462             }
6463             docReadyEvent.addListener(fn, scope, options);
6464         },
6465         
6466         /**
6467          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6468          * @param {Function} fn        The method the event invokes
6469          * @param {Object}   scope    An object that becomes the scope of the handler
6470          * @param {boolean}  options
6471          */
6472         onWindowResize : function(fn, scope, options){
6473             if(!resizeEvent){
6474                 resizeEvent = new Roo.util.Event();
6475                 resizeTask = new Roo.util.DelayedTask(function(){
6476                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6477                 });
6478                 E.on(window, "resize", function(){
6479                     if(Roo.isIE){
6480                         resizeTask.delay(50);
6481                     }else{
6482                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483                     }
6484                 });
6485             }
6486             resizeEvent.addListener(fn, scope, options);
6487         },
6488
6489         /**
6490          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6491          * @param {Function} fn        The method the event invokes
6492          * @param {Object}   scope    An object that becomes the scope of the handler
6493          * @param {boolean}  options
6494          */
6495         onTextResize : function(fn, scope, options){
6496             if(!textEvent){
6497                 textEvent = new Roo.util.Event();
6498                 var textEl = new Roo.Element(document.createElement('div'));
6499                 textEl.dom.className = 'x-text-resize';
6500                 textEl.dom.innerHTML = 'X';
6501                 textEl.appendTo(document.body);
6502                 textSize = textEl.dom.offsetHeight;
6503                 setInterval(function(){
6504                     if(textEl.dom.offsetHeight != textSize){
6505                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6506                     }
6507                 }, this.textResizeInterval);
6508             }
6509             textEvent.addListener(fn, scope, options);
6510         },
6511
6512         /**
6513          * Removes the passed window resize listener.
6514          * @param {Function} fn        The method the event invokes
6515          * @param {Object}   scope    The scope of handler
6516          */
6517         removeResizeListener : function(fn, scope){
6518             if(resizeEvent){
6519                 resizeEvent.removeListener(fn, scope);
6520             }
6521         },
6522
6523         // private
6524         fireResize : function(){
6525             if(resizeEvent){
6526                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527             }   
6528         },
6529         /**
6530          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531          */
6532         ieDeferSrc : false,
6533         /**
6534          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6535          */
6536         textResizeInterval : 50
6537     };
6538     
6539     /**
6540      * Fix for doc tools
6541      * @scopeAlias pub=Roo.EventManager
6542      */
6543     
6544      /**
6545      * Appends an event handler to an element (shorthand for addListener)
6546      * @param {String/HTMLElement}   element        The html element or id to assign the
6547      * @param {String}   eventName The type of event to listen for
6548      * @param {Function} handler The method the event invokes
6549      * @param {Object}   scope (optional) The scope in which to execute the handler
6550      * function. The handler function's "this" context.
6551      * @param {Object}   options (optional) An object containing handler configuration
6552      * properties. This may contain any of the following properties:<ul>
6553      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6554      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6555      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6556      * <li>preventDefault {Boolean} True to prevent the default action</li>
6557      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6558      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6559      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6560      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6561      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6562      * by the specified number of milliseconds. If the event fires again within that time, the original
6563      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6564      * </ul><br>
6565      * <p>
6566      * <b>Combining Options</b><br>
6567      * Using the options argument, it is possible to combine different types of listeners:<br>
6568      * <br>
6569      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6570      * Code:<pre><code>
6571 el.on('click', this.onClick, this, {
6572     single: true,
6573     delay: 100,
6574     stopEvent : true,
6575     forumId: 4
6576 });</code></pre>
6577      * <p>
6578      * <b>Attaching multiple handlers in 1 call</b><br>
6579       * The method also allows for a single argument to be passed which is a config object containing properties
6580      * which specify multiple handlers.
6581      * <p>
6582      * Code:<pre><code>
6583 el.on({
6584     'click' : {
6585         fn: this.onClick
6586         scope: this,
6587         delay: 100
6588     },
6589     'mouseover' : {
6590         fn: this.onMouseOver
6591         scope: this
6592     },
6593     'mouseout' : {
6594         fn: this.onMouseOut
6595         scope: this
6596     }
6597 });</code></pre>
6598      * <p>
6599      * Or a shorthand syntax:<br>
6600      * Code:<pre><code>
6601 el.on({
6602     'click' : this.onClick,
6603     'mouseover' : this.onMouseOver,
6604     'mouseout' : this.onMouseOut
6605     scope: this
6606 });</code></pre>
6607      */
6608     pub.on = pub.addListener;
6609     pub.un = pub.removeListener;
6610
6611     pub.stoppedMouseDownEvent = new Roo.util.Event();
6612     return pub;
6613 }();
6614 /**
6615   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6616   * @param {Function} fn        The method the event invokes
6617   * @param {Object}   scope    An  object that becomes the scope of the handler
6618   * @param {boolean}  override If true, the obj passed in becomes
6619   *                             the execution scope of the listener
6620   * @member Roo
6621   * @method onReady
6622  */
6623 Roo.onReady = Roo.EventManager.onDocumentReady;
6624
6625 Roo.onReady(function(){
6626     var bd = Roo.get(document.body);
6627     if(!bd){ return; }
6628
6629     var cls = [
6630             Roo.isIE ? "roo-ie"
6631             : Roo.isGecko ? "roo-gecko"
6632             : Roo.isOpera ? "roo-opera"
6633             : Roo.isSafari ? "roo-safari" : ""];
6634
6635     if(Roo.isMac){
6636         cls.push("roo-mac");
6637     }
6638     if(Roo.isLinux){
6639         cls.push("roo-linux");
6640     }
6641     if(Roo.isIOS){
6642         cls.push("roo-ios");
6643     }
6644     if(Roo.isTouch){
6645         cls.push("roo-touch");
6646     }
6647     if(Roo.isBorderBox){
6648         cls.push('roo-border-box');
6649     }
6650     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6651         var p = bd.dom.parentNode;
6652         if(p){
6653             p.className += ' roo-strict';
6654         }
6655     }
6656     bd.addClass(cls.join(' '));
6657 });
6658
6659 /**
6660  * @class Roo.EventObject
6661  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6662  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6663  * Example:
6664  * <pre><code>
6665  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6666     e.preventDefault();
6667     var target = e.getTarget();
6668     ...
6669  }
6670  var myDiv = Roo.get("myDiv");
6671  myDiv.on("click", handleClick);
6672  //or
6673  Roo.EventManager.on("myDiv", 'click', handleClick);
6674  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675  </code></pre>
6676  * @singleton
6677  */
6678 Roo.EventObject = function(){
6679     
6680     var E = Roo.lib.Event;
6681     
6682     // safari keypress events for special keys return bad keycodes
6683     var safariKeys = {
6684         63234 : 37, // left
6685         63235 : 39, // right
6686         63232 : 38, // up
6687         63233 : 40, // down
6688         63276 : 33, // page up
6689         63277 : 34, // page down
6690         63272 : 46, // delete
6691         63273 : 36, // home
6692         63275 : 35  // end
6693     };
6694
6695     // normalize button clicks
6696     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6697                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6698
6699     Roo.EventObjectImpl = function(e){
6700         if(e){
6701             this.setEvent(e.browserEvent || e);
6702         }
6703     };
6704     Roo.EventObjectImpl.prototype = {
6705         /**
6706          * Used to fix doc tools.
6707          * @scope Roo.EventObject.prototype
6708          */
6709             
6710
6711         
6712         
6713         /** The normal browser event */
6714         browserEvent : null,
6715         /** The button pressed in a mouse event */
6716         button : -1,
6717         /** True if the shift key was down during the event */
6718         shiftKey : false,
6719         /** True if the control key was down during the event */
6720         ctrlKey : false,
6721         /** True if the alt key was down during the event */
6722         altKey : false,
6723
6724         /** Key constant 
6725         * @type Number */
6726         BACKSPACE : 8,
6727         /** Key constant 
6728         * @type Number */
6729         TAB : 9,
6730         /** Key constant 
6731         * @type Number */
6732         RETURN : 13,
6733         /** Key constant 
6734         * @type Number */
6735         ENTER : 13,
6736         /** Key constant 
6737         * @type Number */
6738         SHIFT : 16,
6739         /** Key constant 
6740         * @type Number */
6741         CONTROL : 17,
6742         /** Key constant 
6743         * @type Number */
6744         ESC : 27,
6745         /** Key constant 
6746         * @type Number */
6747         SPACE : 32,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEUP : 33,
6751         /** Key constant 
6752         * @type Number */
6753         PAGEDOWN : 34,
6754         /** Key constant 
6755         * @type Number */
6756         END : 35,
6757         /** Key constant 
6758         * @type Number */
6759         HOME : 36,
6760         /** Key constant 
6761         * @type Number */
6762         LEFT : 37,
6763         /** Key constant 
6764         * @type Number */
6765         UP : 38,
6766         /** Key constant 
6767         * @type Number */
6768         RIGHT : 39,
6769         /** Key constant 
6770         * @type Number */
6771         DOWN : 40,
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          * Looks at  the scrollable parent element
7171          */
7172         findScrollableParent : function()
7173         {
7174             var overflowRegex = /(auto|scroll)/;
7175             
7176             if(this.getStyle('position') === 'fixed'){
7177                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7178             }
7179             
7180             var excludeStaticParent = this.getStyle('position') === "absolute";
7181             
7182             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7183                 
7184                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7185                     continue;
7186                 }
7187                 
7188                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7189                     return parent;
7190                 }
7191                 
7192                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7193                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7194                 }
7195             }
7196             
7197             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7198         },
7199
7200         /**
7201          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7202          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7203          * @param {String} selector The simple selector to test
7204          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7205                 search as a number or element (defaults to 10 || document.body)
7206          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7207          */
7208         up : function(simpleSelector, maxDepth){
7209             return this.findParentNode(simpleSelector, maxDepth, true);
7210         },
7211
7212
7213
7214         /**
7215          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7216          * @param {String} selector The simple selector to test
7217          * @return {Boolean} True if this element matches the selector, else false
7218          */
7219         is : function(simpleSelector){
7220             return Roo.DomQuery.is(this.dom, simpleSelector);
7221         },
7222
7223         /**
7224          * Perform animation on this element.
7225          * @param {Object} args The YUI animation control args
7226          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7227          * @param {Function} onComplete (optional) Function to call when animation completes
7228          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7229          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7230          * @return {Roo.Element} this
7231          */
7232         animate : function(args, duration, onComplete, easing, animType){
7233             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7234             return this;
7235         },
7236
7237         /*
7238          * @private Internal animation call
7239          */
7240         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7241             animType = animType || 'run';
7242             opt = opt || {};
7243             var anim = Roo.lib.Anim[animType](
7244                 this.dom, args,
7245                 (opt.duration || defaultDur) || .35,
7246                 (opt.easing || defaultEase) || 'easeOut',
7247                 function(){
7248                     Roo.callback(cb, this);
7249                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7250                 },
7251                 this
7252             );
7253             opt.anim = anim;
7254             return anim;
7255         },
7256
7257         // private legacy anim prep
7258         preanim : function(a, i){
7259             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7260         },
7261
7262         /**
7263          * Removes worthless text nodes
7264          * @param {Boolean} forceReclean (optional) By default the element
7265          * keeps track if it has been cleaned already so
7266          * you can call this over and over. However, if you update the element and
7267          * need to force a reclean, you can pass true.
7268          */
7269         clean : function(forceReclean){
7270             if(this.isCleaned && forceReclean !== true){
7271                 return this;
7272             }
7273             var ns = /\S/;
7274             var d = this.dom, n = d.firstChild, ni = -1;
7275             while(n){
7276                 var nx = n.nextSibling;
7277                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7278                     d.removeChild(n);
7279                 }else{
7280                     n.nodeIndex = ++ni;
7281                 }
7282                 n = nx;
7283             }
7284             this.isCleaned = true;
7285             return this;
7286         },
7287
7288         // private
7289         calcOffsetsTo : function(el){
7290             el = Roo.get(el);
7291             var d = el.dom;
7292             var restorePos = false;
7293             if(el.getStyle('position') == 'static'){
7294                 el.position('relative');
7295                 restorePos = true;
7296             }
7297             var x = 0, y =0;
7298             var op = this.dom;
7299             while(op && op != d && op.tagName != 'HTML'){
7300                 x+= op.offsetLeft;
7301                 y+= op.offsetTop;
7302                 op = op.offsetParent;
7303             }
7304             if(restorePos){
7305                 el.position('static');
7306             }
7307             return [x, y];
7308         },
7309
7310         /**
7311          * Scrolls this element into view within the passed container.
7312          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7313          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7314          * @return {Roo.Element} this
7315          */
7316         scrollIntoView : function(container, hscroll){
7317             var c = Roo.getDom(container) || document.body;
7318             var el = this.dom;
7319
7320             var o = this.calcOffsetsTo(c),
7321                 l = o[0],
7322                 t = o[1],
7323                 b = t+el.offsetHeight,
7324                 r = l+el.offsetWidth;
7325
7326             var ch = c.clientHeight;
7327             var ct = parseInt(c.scrollTop, 10);
7328             var cl = parseInt(c.scrollLeft, 10);
7329             var cb = ct + ch;
7330             var cr = cl + c.clientWidth;
7331
7332             if(t < ct){
7333                 c.scrollTop = t;
7334             }else if(b > cb){
7335                 c.scrollTop = b-ch;
7336             }
7337
7338             if(hscroll !== false){
7339                 if(l < cl){
7340                     c.scrollLeft = l;
7341                 }else if(r > cr){
7342                     c.scrollLeft = r-c.clientWidth;
7343                 }
7344             }
7345             return this;
7346         },
7347
7348         // private
7349         scrollChildIntoView : function(child, hscroll){
7350             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7351         },
7352
7353         /**
7354          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7355          * the new height may not be available immediately.
7356          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7357          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7358          * @param {Function} onComplete (optional) Function to call when animation completes
7359          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7360          * @return {Roo.Element} this
7361          */
7362         autoHeight : function(animate, duration, onComplete, easing){
7363             var oldHeight = this.getHeight();
7364             this.clip();
7365             this.setHeight(1); // force clipping
7366             setTimeout(function(){
7367                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7368                 if(!animate){
7369                     this.setHeight(height);
7370                     this.unclip();
7371                     if(typeof onComplete == "function"){
7372                         onComplete();
7373                     }
7374                 }else{
7375                     this.setHeight(oldHeight); // restore original height
7376                     this.setHeight(height, animate, duration, function(){
7377                         this.unclip();
7378                         if(typeof onComplete == "function") { onComplete(); }
7379                     }.createDelegate(this), easing);
7380                 }
7381             }.createDelegate(this), 0);
7382             return this;
7383         },
7384
7385         /**
7386          * Returns true if this element is an ancestor of the passed element
7387          * @param {HTMLElement/String} el The element to check
7388          * @return {Boolean} True if this element is an ancestor of el, else false
7389          */
7390         contains : function(el){
7391             if(!el){return false;}
7392             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7393         },
7394
7395         /**
7396          * Checks whether the element is currently visible using both visibility and display properties.
7397          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7398          * @return {Boolean} True if the element is currently visible, else false
7399          */
7400         isVisible : function(deep) {
7401             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7402             if(deep !== true || !vis){
7403                 return vis;
7404             }
7405             var p = this.dom.parentNode;
7406             while(p && p.tagName.toLowerCase() != "body"){
7407                 if(!Roo.fly(p, '_isVisible').isVisible()){
7408                     return false;
7409                 }
7410                 p = p.parentNode;
7411             }
7412             return true;
7413         },
7414
7415         /**
7416          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7417          * @param {String} selector The CSS selector
7418          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7419          * @return {CompositeElement/CompositeElementLite} The composite element
7420          */
7421         select : function(selector, unique){
7422             return El.select(selector, unique, this.dom);
7423         },
7424
7425         /**
7426          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7427          * @param {String} selector The CSS selector
7428          * @return {Array} An array of the matched nodes
7429          */
7430         query : function(selector, unique){
7431             return Roo.DomQuery.select(selector, this.dom);
7432         },
7433
7434         /**
7435          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7436          * @param {String} selector The CSS selector
7437          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7438          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7439          */
7440         child : function(selector, returnDom){
7441             var n = Roo.DomQuery.selectNode(selector, this.dom);
7442             return returnDom ? n : Roo.get(n);
7443         },
7444
7445         /**
7446          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7447          * @param {String} selector The CSS selector
7448          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7449          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7450          */
7451         down : function(selector, returnDom){
7452             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7453             return returnDom ? n : Roo.get(n);
7454         },
7455
7456         /**
7457          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7458          * @param {String} group The group the DD object is member of
7459          * @param {Object} config The DD config object
7460          * @param {Object} overrides An object containing methods to override/implement on the DD object
7461          * @return {Roo.dd.DD} The DD object
7462          */
7463         initDD : function(group, config, overrides){
7464             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7465             return Roo.apply(dd, overrides);
7466         },
7467
7468         /**
7469          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7470          * @param {String} group The group the DDProxy object is member of
7471          * @param {Object} config The DDProxy config object
7472          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7473          * @return {Roo.dd.DDProxy} The DDProxy object
7474          */
7475         initDDProxy : function(group, config, overrides){
7476             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7477             return Roo.apply(dd, overrides);
7478         },
7479
7480         /**
7481          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7482          * @param {String} group The group the DDTarget object is member of
7483          * @param {Object} config The DDTarget config object
7484          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7485          * @return {Roo.dd.DDTarget} The DDTarget object
7486          */
7487         initDDTarget : function(group, config, overrides){
7488             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7489             return Roo.apply(dd, overrides);
7490         },
7491
7492         /**
7493          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7494          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7495          * @param {Boolean} visible Whether the element is visible
7496          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497          * @return {Roo.Element} this
7498          */
7499          setVisible : function(visible, animate){
7500             if(!animate || !A){
7501                 if(this.visibilityMode == El.DISPLAY){
7502                     this.setDisplayed(visible);
7503                 }else{
7504                     this.fixDisplay();
7505                     this.dom.style.visibility = visible ? "visible" : "hidden";
7506                 }
7507             }else{
7508                 // closure for composites
7509                 var dom = this.dom;
7510                 var visMode = this.visibilityMode;
7511                 if(visible){
7512                     this.setOpacity(.01);
7513                     this.setVisible(true);
7514                 }
7515                 this.anim({opacity: { to: (visible?1:0) }},
7516                       this.preanim(arguments, 1),
7517                       null, .35, 'easeIn', function(){
7518                          if(!visible){
7519                              if(visMode == El.DISPLAY){
7520                                  dom.style.display = "none";
7521                              }else{
7522                                  dom.style.visibility = "hidden";
7523                              }
7524                              Roo.get(dom).setOpacity(1);
7525                          }
7526                      });
7527             }
7528             return this;
7529         },
7530
7531         /**
7532          * Returns true if display is not "none"
7533          * @return {Boolean}
7534          */
7535         isDisplayed : function() {
7536             return this.getStyle("display") != "none";
7537         },
7538
7539         /**
7540          * Toggles the element's visibility or display, depending on visibility mode.
7541          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7542          * @return {Roo.Element} this
7543          */
7544         toggle : function(animate){
7545             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7546             return this;
7547         },
7548
7549         /**
7550          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7551          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7552          * @return {Roo.Element} this
7553          */
7554         setDisplayed : function(value) {
7555             if(typeof value == "boolean"){
7556                value = value ? this.originalDisplay : "none";
7557             }
7558             this.setStyle("display", value);
7559             return this;
7560         },
7561
7562         /**
7563          * Tries to focus the element. Any exceptions are caught and ignored.
7564          * @return {Roo.Element} this
7565          */
7566         focus : function() {
7567             try{
7568                 this.dom.focus();
7569             }catch(e){}
7570             return this;
7571         },
7572
7573         /**
7574          * Tries to blur the element. Any exceptions are caught and ignored.
7575          * @return {Roo.Element} this
7576          */
7577         blur : function() {
7578             try{
7579                 this.dom.blur();
7580             }catch(e){}
7581             return this;
7582         },
7583
7584         /**
7585          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7586          * @param {String/Array} className The CSS class to add, or an array of classes
7587          * @return {Roo.Element} this
7588          */
7589         addClass : function(className){
7590             if(className instanceof Array){
7591                 for(var i = 0, len = className.length; i < len; i++) {
7592                     this.addClass(className[i]);
7593                 }
7594             }else{
7595                 if(className && !this.hasClass(className)){
7596                     this.dom.className = this.dom.className + " " + className;
7597                 }
7598             }
7599             return this;
7600         },
7601
7602         /**
7603          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7604          * @param {String/Array} className The CSS class to add, or an array of classes
7605          * @return {Roo.Element} this
7606          */
7607         radioClass : function(className){
7608             var siblings = this.dom.parentNode.childNodes;
7609             for(var i = 0; i < siblings.length; i++) {
7610                 var s = siblings[i];
7611                 if(s.nodeType == 1){
7612                     Roo.get(s).removeClass(className);
7613                 }
7614             }
7615             this.addClass(className);
7616             return this;
7617         },
7618
7619         /**
7620          * Removes one or more CSS classes from the element.
7621          * @param {String/Array} className The CSS class to remove, or an array of classes
7622          * @return {Roo.Element} this
7623          */
7624         removeClass : function(className){
7625             if(!className || !this.dom.className){
7626                 return this;
7627             }
7628             if(className instanceof Array){
7629                 for(var i = 0, len = className.length; i < len; i++) {
7630                     this.removeClass(className[i]);
7631                 }
7632             }else{
7633                 if(this.hasClass(className)){
7634                     var re = this.classReCache[className];
7635                     if (!re) {
7636                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7637                        this.classReCache[className] = re;
7638                     }
7639                     this.dom.className =
7640                         this.dom.className.replace(re, " ");
7641                 }
7642             }
7643             return this;
7644         },
7645
7646         // private
7647         classReCache: {},
7648
7649         /**
7650          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7651          * @param {String} className The CSS class to toggle
7652          * @return {Roo.Element} this
7653          */
7654         toggleClass : function(className){
7655             if(this.hasClass(className)){
7656                 this.removeClass(className);
7657             }else{
7658                 this.addClass(className);
7659             }
7660             return this;
7661         },
7662
7663         /**
7664          * Checks if the specified CSS class exists on this element's DOM node.
7665          * @param {String} className The CSS class to check for
7666          * @return {Boolean} True if the class exists, else false
7667          */
7668         hasClass : function(className){
7669             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7670         },
7671
7672         /**
7673          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7674          * @param {String} oldClassName The CSS class to replace
7675          * @param {String} newClassName The replacement CSS class
7676          * @return {Roo.Element} this
7677          */
7678         replaceClass : function(oldClassName, newClassName){
7679             this.removeClass(oldClassName);
7680             this.addClass(newClassName);
7681             return this;
7682         },
7683
7684         /**
7685          * Returns an object with properties matching the styles requested.
7686          * For example, el.getStyles('color', 'font-size', 'width') might return
7687          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7688          * @param {String} style1 A style name
7689          * @param {String} style2 A style name
7690          * @param {String} etc.
7691          * @return {Object} The style object
7692          */
7693         getStyles : function(){
7694             var a = arguments, len = a.length, r = {};
7695             for(var i = 0; i < len; i++){
7696                 r[a[i]] = this.getStyle(a[i]);
7697             }
7698             return r;
7699         },
7700
7701         /**
7702          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7703          * @param {String} property The style property whose value is returned.
7704          * @return {String} The current value of the style property for this element.
7705          */
7706         getStyle : function(){
7707             return view && view.getComputedStyle ?
7708                 function(prop){
7709                     var el = this.dom, v, cs, camel;
7710                     if(prop == 'float'){
7711                         prop = "cssFloat";
7712                     }
7713                     if(el.style && (v = el.style[prop])){
7714                         return v;
7715                     }
7716                     if(cs = view.getComputedStyle(el, "")){
7717                         if(!(camel = propCache[prop])){
7718                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7719                         }
7720                         return cs[camel];
7721                     }
7722                     return null;
7723                 } :
7724                 function(prop){
7725                     var el = this.dom, v, cs, camel;
7726                     if(prop == 'opacity'){
7727                         if(typeof el.style.filter == 'string'){
7728                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7729                             if(m){
7730                                 var fv = parseFloat(m[1]);
7731                                 if(!isNaN(fv)){
7732                                     return fv ? fv / 100 : 0;
7733                                 }
7734                             }
7735                         }
7736                         return 1;
7737                     }else if(prop == 'float'){
7738                         prop = "styleFloat";
7739                     }
7740                     if(!(camel = propCache[prop])){
7741                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7742                     }
7743                     if(v = el.style[camel]){
7744                         return v;
7745                     }
7746                     if(cs = el.currentStyle){
7747                         return cs[camel];
7748                     }
7749                     return null;
7750                 };
7751         }(),
7752
7753         /**
7754          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7755          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7756          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7757          * @return {Roo.Element} this
7758          */
7759         setStyle : function(prop, value){
7760             if(typeof prop == "string"){
7761                 
7762                 if (prop == 'float') {
7763                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7764                     return this;
7765                 }
7766                 
7767                 var camel;
7768                 if(!(camel = propCache[prop])){
7769                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7770                 }
7771                 
7772                 if(camel == 'opacity') {
7773                     this.setOpacity(value);
7774                 }else{
7775                     this.dom.style[camel] = value;
7776                 }
7777             }else{
7778                 for(var style in prop){
7779                     if(typeof prop[style] != "function"){
7780                        this.setStyle(style, prop[style]);
7781                     }
7782                 }
7783             }
7784             return this;
7785         },
7786
7787         /**
7788          * More flexible version of {@link #setStyle} for setting style properties.
7789          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7790          * a function which returns such a specification.
7791          * @return {Roo.Element} this
7792          */
7793         applyStyles : function(style){
7794             Roo.DomHelper.applyStyles(this.dom, style);
7795             return this;
7796         },
7797
7798         /**
7799           * 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).
7800           * @return {Number} The X position of the element
7801           */
7802         getX : function(){
7803             return D.getX(this.dom);
7804         },
7805
7806         /**
7807           * 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).
7808           * @return {Number} The Y position of the element
7809           */
7810         getY : function(){
7811             return D.getY(this.dom);
7812         },
7813
7814         /**
7815           * 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).
7816           * @return {Array} The XY position of the element
7817           */
7818         getXY : function(){
7819             return D.getXY(this.dom);
7820         },
7821
7822         /**
7823          * 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).
7824          * @param {Number} The X position of the element
7825          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826          * @return {Roo.Element} this
7827          */
7828         setX : function(x, animate){
7829             if(!animate || !A){
7830                 D.setX(this.dom, x);
7831             }else{
7832                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7833             }
7834             return this;
7835         },
7836
7837         /**
7838          * 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).
7839          * @param {Number} The Y position of the element
7840          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841          * @return {Roo.Element} this
7842          */
7843         setY : function(y, animate){
7844             if(!animate || !A){
7845                 D.setY(this.dom, y);
7846             }else{
7847                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7848             }
7849             return this;
7850         },
7851
7852         /**
7853          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7854          * @param {String} left The left CSS property value
7855          * @return {Roo.Element} this
7856          */
7857         setLeft : function(left){
7858             this.setStyle("left", this.addUnits(left));
7859             return this;
7860         },
7861
7862         /**
7863          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7864          * @param {String} top The top CSS property value
7865          * @return {Roo.Element} this
7866          */
7867         setTop : function(top){
7868             this.setStyle("top", this.addUnits(top));
7869             return this;
7870         },
7871
7872         /**
7873          * Sets the element's CSS right style.
7874          * @param {String} right The right CSS property value
7875          * @return {Roo.Element} this
7876          */
7877         setRight : function(right){
7878             this.setStyle("right", this.addUnits(right));
7879             return this;
7880         },
7881
7882         /**
7883          * Sets the element's CSS bottom style.
7884          * @param {String} bottom The bottom CSS property value
7885          * @return {Roo.Element} this
7886          */
7887         setBottom : function(bottom){
7888             this.setStyle("bottom", this.addUnits(bottom));
7889             return this;
7890         },
7891
7892         /**
7893          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7894          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7895          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7896          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7897          * @return {Roo.Element} this
7898          */
7899         setXY : function(pos, animate){
7900             if(!animate || !A){
7901                 D.setXY(this.dom, pos);
7902             }else{
7903                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7904             }
7905             return this;
7906         },
7907
7908         /**
7909          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7910          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7911          * @param {Number} x X value for new position (coordinates are page-based)
7912          * @param {Number} y Y value for new position (coordinates are page-based)
7913          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7914          * @return {Roo.Element} this
7915          */
7916         setLocation : function(x, y, animate){
7917             this.setXY([x, y], this.preanim(arguments, 2));
7918             return this;
7919         },
7920
7921         /**
7922          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7923          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7924          * @param {Number} x X value for new position (coordinates are page-based)
7925          * @param {Number} y Y value for new position (coordinates are page-based)
7926          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7927          * @return {Roo.Element} this
7928          */
7929         moveTo : function(x, y, animate){
7930             this.setXY([x, y], this.preanim(arguments, 2));
7931             return this;
7932         },
7933
7934         /**
7935          * Returns the region of the given element.
7936          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7937          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7938          */
7939         getRegion : function(){
7940             return D.getRegion(this.dom);
7941         },
7942
7943         /**
7944          * Returns the offset height of the element
7945          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7946          * @return {Number} The element's height
7947          */
7948         getHeight : function(contentHeight){
7949             var h = this.dom.offsetHeight || 0;
7950             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7951         },
7952
7953         /**
7954          * Returns the offset width of the element
7955          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7956          * @return {Number} The element's width
7957          */
7958         getWidth : function(contentWidth){
7959             var w = this.dom.offsetWidth || 0;
7960             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7961         },
7962
7963         /**
7964          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7965          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7966          * if a height has not been set using CSS.
7967          * @return {Number}
7968          */
7969         getComputedHeight : function(){
7970             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7971             if(!h){
7972                 h = parseInt(this.getStyle('height'), 10) || 0;
7973                 if(!this.isBorderBox()){
7974                     h += this.getFrameWidth('tb');
7975                 }
7976             }
7977             return h;
7978         },
7979
7980         /**
7981          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7982          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7983          * if a width has not been set using CSS.
7984          * @return {Number}
7985          */
7986         getComputedWidth : function(){
7987             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7988             if(!w){
7989                 w = parseInt(this.getStyle('width'), 10) || 0;
7990                 if(!this.isBorderBox()){
7991                     w += this.getFrameWidth('lr');
7992                 }
7993             }
7994             return w;
7995         },
7996
7997         /**
7998          * Returns the size of the element.
7999          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8000          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8001          */
8002         getSize : function(contentSize){
8003             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8004         },
8005
8006         /**
8007          * Returns the width and height of the viewport.
8008          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8009          */
8010         getViewSize : function(){
8011             var d = this.dom, doc = document, aw = 0, ah = 0;
8012             if(d == doc || d == doc.body){
8013                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8014             }else{
8015                 return {
8016                     width : d.clientWidth,
8017                     height: d.clientHeight
8018                 };
8019             }
8020         },
8021
8022         /**
8023          * Returns the value of the "value" attribute
8024          * @param {Boolean} asNumber true to parse the value as a number
8025          * @return {String/Number}
8026          */
8027         getValue : function(asNumber){
8028             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8029         },
8030
8031         // private
8032         adjustWidth : function(width){
8033             if(typeof width == "number"){
8034                 if(this.autoBoxAdjust && !this.isBorderBox()){
8035                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8036                 }
8037                 if(width < 0){
8038                     width = 0;
8039                 }
8040             }
8041             return width;
8042         },
8043
8044         // private
8045         adjustHeight : function(height){
8046             if(typeof height == "number"){
8047                if(this.autoBoxAdjust && !this.isBorderBox()){
8048                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8049                }
8050                if(height < 0){
8051                    height = 0;
8052                }
8053             }
8054             return height;
8055         },
8056
8057         /**
8058          * Set the width of the element
8059          * @param {Number} width The new width
8060          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8061          * @return {Roo.Element} this
8062          */
8063         setWidth : function(width, animate){
8064             width = this.adjustWidth(width);
8065             if(!animate || !A){
8066                 this.dom.style.width = this.addUnits(width);
8067             }else{
8068                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8069             }
8070             return this;
8071         },
8072
8073         /**
8074          * Set the height of the element
8075          * @param {Number} height The new height
8076          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8077          * @return {Roo.Element} this
8078          */
8079          setHeight : function(height, animate){
8080             height = this.adjustHeight(height);
8081             if(!animate || !A){
8082                 this.dom.style.height = this.addUnits(height);
8083             }else{
8084                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8085             }
8086             return this;
8087         },
8088
8089         /**
8090          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8091          * @param {Number} width The new width
8092          * @param {Number} height The new height
8093          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8094          * @return {Roo.Element} this
8095          */
8096          setSize : function(width, height, animate){
8097             if(typeof width == "object"){ // in case of object from getSize()
8098                 height = width.height; width = width.width;
8099             }
8100             width = this.adjustWidth(width); height = this.adjustHeight(height);
8101             if(!animate || !A){
8102                 this.dom.style.width = this.addUnits(width);
8103                 this.dom.style.height = this.addUnits(height);
8104             }else{
8105                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8106             }
8107             return this;
8108         },
8109
8110         /**
8111          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8112          * @param {Number} x X value for new position (coordinates are page-based)
8113          * @param {Number} y Y value for new position (coordinates are page-based)
8114          * @param {Number} width The new width
8115          * @param {Number} height The new height
8116          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8117          * @return {Roo.Element} this
8118          */
8119         setBounds : function(x, y, width, height, animate){
8120             if(!animate || !A){
8121                 this.setSize(width, height);
8122                 this.setLocation(x, y);
8123             }else{
8124                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8125                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8126                               this.preanim(arguments, 4), 'motion');
8127             }
8128             return this;
8129         },
8130
8131         /**
8132          * 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.
8133          * @param {Roo.lib.Region} region The region to fill
8134          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8135          * @return {Roo.Element} this
8136          */
8137         setRegion : function(region, animate){
8138             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8139             return this;
8140         },
8141
8142         /**
8143          * Appends an event handler
8144          *
8145          * @param {String}   eventName     The type of event to append
8146          * @param {Function} fn        The method the event invokes
8147          * @param {Object} scope       (optional) The scope (this object) of the fn
8148          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8149          */
8150         addListener : function(eventName, fn, scope, options){
8151             if (this.dom) {
8152                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8153             }
8154         },
8155
8156         /**
8157          * Removes an event handler from this element
8158          * @param {String} eventName the type of event to remove
8159          * @param {Function} fn the method the event invokes
8160          * @return {Roo.Element} this
8161          */
8162         removeListener : function(eventName, fn){
8163             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8164             return this;
8165         },
8166
8167         /**
8168          * Removes all previous added listeners from this element
8169          * @return {Roo.Element} this
8170          */
8171         removeAllListeners : function(){
8172             E.purgeElement(this.dom);
8173             return this;
8174         },
8175
8176         relayEvent : function(eventName, observable){
8177             this.on(eventName, function(e){
8178                 observable.fireEvent(eventName, e);
8179             });
8180         },
8181
8182         /**
8183          * Set the opacity of the element
8184          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8185          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8186          * @return {Roo.Element} this
8187          */
8188          setOpacity : function(opacity, animate){
8189             if(!animate || !A){
8190                 var s = this.dom.style;
8191                 if(Roo.isIE){
8192                     s.zoom = 1;
8193                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8194                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8195                 }else{
8196                     s.opacity = opacity;
8197                 }
8198             }else{
8199                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8200             }
8201             return this;
8202         },
8203
8204         /**
8205          * Gets the left X coordinate
8206          * @param {Boolean} local True to get the local css position instead of page coordinate
8207          * @return {Number}
8208          */
8209         getLeft : function(local){
8210             if(!local){
8211                 return this.getX();
8212             }else{
8213                 return parseInt(this.getStyle("left"), 10) || 0;
8214             }
8215         },
8216
8217         /**
8218          * Gets the right X coordinate of the element (element X position + element width)
8219          * @param {Boolean} local True to get the local css position instead of page coordinate
8220          * @return {Number}
8221          */
8222         getRight : function(local){
8223             if(!local){
8224                 return this.getX() + this.getWidth();
8225             }else{
8226                 return (this.getLeft(true) + this.getWidth()) || 0;
8227             }
8228         },
8229
8230         /**
8231          * Gets the top Y coordinate
8232          * @param {Boolean} local True to get the local css position instead of page coordinate
8233          * @return {Number}
8234          */
8235         getTop : function(local) {
8236             if(!local){
8237                 return this.getY();
8238             }else{
8239                 return parseInt(this.getStyle("top"), 10) || 0;
8240             }
8241         },
8242
8243         /**
8244          * Gets the bottom Y coordinate of the element (element Y position + element height)
8245          * @param {Boolean} local True to get the local css position instead of page coordinate
8246          * @return {Number}
8247          */
8248         getBottom : function(local){
8249             if(!local){
8250                 return this.getY() + this.getHeight();
8251             }else{
8252                 return (this.getTop(true) + this.getHeight()) || 0;
8253             }
8254         },
8255
8256         /**
8257         * Initializes positioning on this element. If a desired position is not passed, it will make the
8258         * the element positioned relative IF it is not already positioned.
8259         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8260         * @param {Number} zIndex (optional) The zIndex to apply
8261         * @param {Number} x (optional) Set the page X position
8262         * @param {Number} y (optional) Set the page Y position
8263         */
8264         position : function(pos, zIndex, x, y){
8265             if(!pos){
8266                if(this.getStyle('position') == 'static'){
8267                    this.setStyle('position', 'relative');
8268                }
8269             }else{
8270                 this.setStyle("position", pos);
8271             }
8272             if(zIndex){
8273                 this.setStyle("z-index", zIndex);
8274             }
8275             if(x !== undefined && y !== undefined){
8276                 this.setXY([x, y]);
8277             }else if(x !== undefined){
8278                 this.setX(x);
8279             }else if(y !== undefined){
8280                 this.setY(y);
8281             }
8282         },
8283
8284         /**
8285         * Clear positioning back to the default when the document was loaded
8286         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8287         * @return {Roo.Element} this
8288          */
8289         clearPositioning : function(value){
8290             value = value ||'';
8291             this.setStyle({
8292                 "left": value,
8293                 "right": value,
8294                 "top": value,
8295                 "bottom": value,
8296                 "z-index": "",
8297                 "position" : "static"
8298             });
8299             return this;
8300         },
8301
8302         /**
8303         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8304         * snapshot before performing an update and then restoring the element.
8305         * @return {Object}
8306         */
8307         getPositioning : function(){
8308             var l = this.getStyle("left");
8309             var t = this.getStyle("top");
8310             return {
8311                 "position" : this.getStyle("position"),
8312                 "left" : l,
8313                 "right" : l ? "" : this.getStyle("right"),
8314                 "top" : t,
8315                 "bottom" : t ? "" : this.getStyle("bottom"),
8316                 "z-index" : this.getStyle("z-index")
8317             };
8318         },
8319
8320         /**
8321          * Gets the width of the border(s) for the specified side(s)
8322          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8323          * passing lr would get the border (l)eft width + the border (r)ight width.
8324          * @return {Number} The width of the sides passed added together
8325          */
8326         getBorderWidth : function(side){
8327             return this.addStyles(side, El.borders);
8328         },
8329
8330         /**
8331          * Gets the width of the padding(s) for the specified side(s)
8332          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8333          * passing lr would get the padding (l)eft + the padding (r)ight.
8334          * @return {Number} The padding of the sides passed added together
8335          */
8336         getPadding : function(side){
8337             return this.addStyles(side, El.paddings);
8338         },
8339
8340         /**
8341         * Set positioning with an object returned by getPositioning().
8342         * @param {Object} posCfg
8343         * @return {Roo.Element} this
8344          */
8345         setPositioning : function(pc){
8346             this.applyStyles(pc);
8347             if(pc.right == "auto"){
8348                 this.dom.style.right = "";
8349             }
8350             if(pc.bottom == "auto"){
8351                 this.dom.style.bottom = "";
8352             }
8353             return this;
8354         },
8355
8356         // private
8357         fixDisplay : function(){
8358             if(this.getStyle("display") == "none"){
8359                 this.setStyle("visibility", "hidden");
8360                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8361                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8362                     this.setStyle("display", "block");
8363                 }
8364             }
8365         },
8366
8367         /**
8368          * Quick set left and top adding default units
8369          * @param {String} left The left CSS property value
8370          * @param {String} top The top CSS property value
8371          * @return {Roo.Element} this
8372          */
8373          setLeftTop : function(left, top){
8374             this.dom.style.left = this.addUnits(left);
8375             this.dom.style.top = this.addUnits(top);
8376             return this;
8377         },
8378
8379         /**
8380          * Move this element relative to its current position.
8381          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8382          * @param {Number} distance How far to move the element in pixels
8383          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8384          * @return {Roo.Element} this
8385          */
8386          move : function(direction, distance, animate){
8387             var xy = this.getXY();
8388             direction = direction.toLowerCase();
8389             switch(direction){
8390                 case "l":
8391                 case "left":
8392                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8393                     break;
8394                case "r":
8395                case "right":
8396                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8397                     break;
8398                case "t":
8399                case "top":
8400                case "up":
8401                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8402                     break;
8403                case "b":
8404                case "bottom":
8405                case "down":
8406                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8407                     break;
8408             }
8409             return this;
8410         },
8411
8412         /**
8413          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8414          * @return {Roo.Element} this
8415          */
8416         clip : function(){
8417             if(!this.isClipped){
8418                this.isClipped = true;
8419                this.originalClip = {
8420                    "o": this.getStyle("overflow"),
8421                    "x": this.getStyle("overflow-x"),
8422                    "y": this.getStyle("overflow-y")
8423                };
8424                this.setStyle("overflow", "hidden");
8425                this.setStyle("overflow-x", "hidden");
8426                this.setStyle("overflow-y", "hidden");
8427             }
8428             return this;
8429         },
8430
8431         /**
8432          *  Return clipping (overflow) to original clipping before clip() was called
8433          * @return {Roo.Element} this
8434          */
8435         unclip : function(){
8436             if(this.isClipped){
8437                 this.isClipped = false;
8438                 var o = this.originalClip;
8439                 if(o.o){this.setStyle("overflow", o.o);}
8440                 if(o.x){this.setStyle("overflow-x", o.x);}
8441                 if(o.y){this.setStyle("overflow-y", o.y);}
8442             }
8443             return this;
8444         },
8445
8446
8447         /**
8448          * Gets the x,y coordinates specified by the anchor position on the element.
8449          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8450          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8451          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8452          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8453          * @return {Array} [x, y] An array containing the element's x and y coordinates
8454          */
8455         getAnchorXY : function(anchor, local, s){
8456             //Passing a different size is useful for pre-calculating anchors,
8457             //especially for anchored animations that change the el size.
8458
8459             var w, h, vp = false;
8460             if(!s){
8461                 var d = this.dom;
8462                 if(d == document.body || d == document){
8463                     vp = true;
8464                     w = D.getViewWidth(); h = D.getViewHeight();
8465                 }else{
8466                     w = this.getWidth(); h = this.getHeight();
8467                 }
8468             }else{
8469                 w = s.width;  h = s.height;
8470             }
8471             var x = 0, y = 0, r = Math.round;
8472             switch((anchor || "tl").toLowerCase()){
8473                 case "c":
8474                     x = r(w*.5);
8475                     y = r(h*.5);
8476                 break;
8477                 case "t":
8478                     x = r(w*.5);
8479                     y = 0;
8480                 break;
8481                 case "l":
8482                     x = 0;
8483                     y = r(h*.5);
8484                 break;
8485                 case "r":
8486                     x = w;
8487                     y = r(h*.5);
8488                 break;
8489                 case "b":
8490                     x = r(w*.5);
8491                     y = h;
8492                 break;
8493                 case "tl":
8494                     x = 0;
8495                     y = 0;
8496                 break;
8497                 case "bl":
8498                     x = 0;
8499                     y = h;
8500                 break;
8501                 case "br":
8502                     x = w;
8503                     y = h;
8504                 break;
8505                 case "tr":
8506                     x = w;
8507                     y = 0;
8508                 break;
8509             }
8510             if(local === true){
8511                 return [x, y];
8512             }
8513             if(vp){
8514                 var sc = this.getScroll();
8515                 return [x + sc.left, y + sc.top];
8516             }
8517             //Add the element's offset xy
8518             var o = this.getXY();
8519             return [x+o[0], y+o[1]];
8520         },
8521
8522         /**
8523          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8524          * supported position values.
8525          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8526          * @param {String} position The position to align to.
8527          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8528          * @return {Array} [x, y]
8529          */
8530         getAlignToXY : function(el, p, o){
8531             el = Roo.get(el);
8532             var d = this.dom;
8533             if(!el.dom){
8534                 throw "Element.alignTo with an element that doesn't exist";
8535             }
8536             var c = false; //constrain to viewport
8537             var p1 = "", p2 = "";
8538             o = o || [0,0];
8539
8540             if(!p){
8541                 p = "tl-bl";
8542             }else if(p == "?"){
8543                 p = "tl-bl?";
8544             }else if(p.indexOf("-") == -1){
8545                 p = "tl-" + p;
8546             }
8547             p = p.toLowerCase();
8548             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8549             if(!m){
8550                throw "Element.alignTo with an invalid alignment " + p;
8551             }
8552             p1 = m[1]; p2 = m[2]; c = !!m[3];
8553
8554             //Subtract the aligned el's internal xy from the target's offset xy
8555             //plus custom offset to get the aligned el's new offset xy
8556             var a1 = this.getAnchorXY(p1, true);
8557             var a2 = el.getAnchorXY(p2, false);
8558             var x = a2[0] - a1[0] + o[0];
8559             var y = a2[1] - a1[1] + o[1];
8560             if(c){
8561                 //constrain the aligned el to viewport if necessary
8562                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8563                 // 5px of margin for ie
8564                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8565
8566                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8567                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8568                 //otherwise swap the aligned el to the opposite border of the target.
8569                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8570                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8571                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8572                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8573
8574                var doc = document;
8575                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8576                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8577
8578                if((x+w) > dw + scrollX){
8579                     x = swapX ? r.left-w : dw+scrollX-w;
8580                 }
8581                if(x < scrollX){
8582                    x = swapX ? r.right : scrollX;
8583                }
8584                if((y+h) > dh + scrollY){
8585                     y = swapY ? r.top-h : dh+scrollY-h;
8586                 }
8587                if (y < scrollY){
8588                    y = swapY ? r.bottom : scrollY;
8589                }
8590             }
8591             return [x,y];
8592         },
8593
8594         // private
8595         getConstrainToXY : function(){
8596             var os = {top:0, left:0, bottom:0, right: 0};
8597
8598             return function(el, local, offsets, proposedXY){
8599                 el = Roo.get(el);
8600                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8601
8602                 var vw, vh, vx = 0, vy = 0;
8603                 if(el.dom == document.body || el.dom == document){
8604                     vw = Roo.lib.Dom.getViewWidth();
8605                     vh = Roo.lib.Dom.getViewHeight();
8606                 }else{
8607                     vw = el.dom.clientWidth;
8608                     vh = el.dom.clientHeight;
8609                     if(!local){
8610                         var vxy = el.getXY();
8611                         vx = vxy[0];
8612                         vy = vxy[1];
8613                     }
8614                 }
8615
8616                 var s = el.getScroll();
8617
8618                 vx += offsets.left + s.left;
8619                 vy += offsets.top + s.top;
8620
8621                 vw -= offsets.right;
8622                 vh -= offsets.bottom;
8623
8624                 var vr = vx+vw;
8625                 var vb = vy+vh;
8626
8627                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8628                 var x = xy[0], y = xy[1];
8629                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8630
8631                 // only move it if it needs it
8632                 var moved = false;
8633
8634                 // first validate right/bottom
8635                 if((x + w) > vr){
8636                     x = vr - w;
8637                     moved = true;
8638                 }
8639                 if((y + h) > vb){
8640                     y = vb - h;
8641                     moved = true;
8642                 }
8643                 // then make sure top/left isn't negative
8644                 if(x < vx){
8645                     x = vx;
8646                     moved = true;
8647                 }
8648                 if(y < vy){
8649                     y = vy;
8650                     moved = true;
8651                 }
8652                 return moved ? [x, y] : false;
8653             };
8654         }(),
8655
8656         // private
8657         adjustForConstraints : function(xy, parent, offsets){
8658             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8659         },
8660
8661         /**
8662          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8663          * document it aligns it to the viewport.
8664          * The position parameter is optional, and can be specified in any one of the following formats:
8665          * <ul>
8666          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8667          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8668          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8669          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8670          *   <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
8671          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8672          * </ul>
8673          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8674          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8675          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8676          * that specified in order to enforce the viewport constraints.
8677          * Following are all of the supported anchor positions:
8678     <pre>
8679     Value  Description
8680     -----  -----------------------------
8681     tl     The top left corner (default)
8682     t      The center of the top edge
8683     tr     The top right corner
8684     l      The center of the left edge
8685     c      In the center of the element
8686     r      The center of the right edge
8687     bl     The bottom left corner
8688     b      The center of the bottom edge
8689     br     The bottom right corner
8690     </pre>
8691     Example Usage:
8692     <pre><code>
8693     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8694     el.alignTo("other-el");
8695
8696     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8697     el.alignTo("other-el", "tr?");
8698
8699     // align the bottom right corner of el with the center left edge of other-el
8700     el.alignTo("other-el", "br-l?");
8701
8702     // align the center of el with the bottom left corner of other-el and
8703     // adjust the x position by -6 pixels (and the y position by 0)
8704     el.alignTo("other-el", "c-bl", [-6, 0]);
8705     </code></pre>
8706          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8707          * @param {String} position The position to align to.
8708          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8709          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8710          * @return {Roo.Element} this
8711          */
8712         alignTo : function(element, position, offsets, animate){
8713             var xy = this.getAlignToXY(element, position, offsets);
8714             this.setXY(xy, this.preanim(arguments, 3));
8715             return this;
8716         },
8717
8718         /**
8719          * Anchors an element to another element and realigns it when the window is resized.
8720          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8721          * @param {String} position The position to align to.
8722          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8723          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8724          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8725          * is a number, it is used as the buffer delay (defaults to 50ms).
8726          * @param {Function} callback The function to call after the animation finishes
8727          * @return {Roo.Element} this
8728          */
8729         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8730             var action = function(){
8731                 this.alignTo(el, alignment, offsets, animate);
8732                 Roo.callback(callback, this);
8733             };
8734             Roo.EventManager.onWindowResize(action, this);
8735             var tm = typeof monitorScroll;
8736             if(tm != 'undefined'){
8737                 Roo.EventManager.on(window, 'scroll', action, this,
8738                     {buffer: tm == 'number' ? monitorScroll : 50});
8739             }
8740             action.call(this); // align immediately
8741             return this;
8742         },
8743         /**
8744          * Clears any opacity settings from this element. Required in some cases for IE.
8745          * @return {Roo.Element} this
8746          */
8747         clearOpacity : function(){
8748             if (window.ActiveXObject) {
8749                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8750                     this.dom.style.filter = "";
8751                 }
8752             } else {
8753                 this.dom.style.opacity = "";
8754                 this.dom.style["-moz-opacity"] = "";
8755                 this.dom.style["-khtml-opacity"] = "";
8756             }
8757             return this;
8758         },
8759
8760         /**
8761          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8762          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8763          * @return {Roo.Element} this
8764          */
8765         hide : function(animate){
8766             this.setVisible(false, this.preanim(arguments, 0));
8767             return this;
8768         },
8769
8770         /**
8771         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8772         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8773          * @return {Roo.Element} this
8774          */
8775         show : function(animate){
8776             this.setVisible(true, this.preanim(arguments, 0));
8777             return this;
8778         },
8779
8780         /**
8781          * @private Test if size has a unit, otherwise appends the default
8782          */
8783         addUnits : function(size){
8784             return Roo.Element.addUnits(size, this.defaultUnit);
8785         },
8786
8787         /**
8788          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8789          * @return {Roo.Element} this
8790          */
8791         beginMeasure : function(){
8792             var el = this.dom;
8793             if(el.offsetWidth || el.offsetHeight){
8794                 return this; // offsets work already
8795             }
8796             var changed = [];
8797             var p = this.dom, b = document.body; // start with this element
8798             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8799                 var pe = Roo.get(p);
8800                 if(pe.getStyle('display') == 'none'){
8801                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8802                     p.style.visibility = "hidden";
8803                     p.style.display = "block";
8804                 }
8805                 p = p.parentNode;
8806             }
8807             this._measureChanged = changed;
8808             return this;
8809
8810         },
8811
8812         /**
8813          * Restores displays to before beginMeasure was called
8814          * @return {Roo.Element} this
8815          */
8816         endMeasure : function(){
8817             var changed = this._measureChanged;
8818             if(changed){
8819                 for(var i = 0, len = changed.length; i < len; i++) {
8820                     var r = changed[i];
8821                     r.el.style.visibility = r.visibility;
8822                     r.el.style.display = "none";
8823                 }
8824                 this._measureChanged = null;
8825             }
8826             return this;
8827         },
8828
8829         /**
8830         * Update the innerHTML of this element, optionally searching for and processing scripts
8831         * @param {String} html The new HTML
8832         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8833         * @param {Function} callback For async script loading you can be noticed when the update completes
8834         * @return {Roo.Element} this
8835          */
8836         update : function(html, loadScripts, callback){
8837             if(typeof html == "undefined"){
8838                 html = "";
8839             }
8840             if(loadScripts !== true){
8841                 this.dom.innerHTML = html;
8842                 if(typeof callback == "function"){
8843                     callback();
8844                 }
8845                 return this;
8846             }
8847             var id = Roo.id();
8848             var dom = this.dom;
8849
8850             html += '<span id="' + id + '"></span>';
8851
8852             E.onAvailable(id, function(){
8853                 var hd = document.getElementsByTagName("head")[0];
8854                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8855                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8856                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8857
8858                 var match;
8859                 while(match = re.exec(html)){
8860                     var attrs = match[1];
8861                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8862                     if(srcMatch && srcMatch[2]){
8863                        var s = document.createElement("script");
8864                        s.src = srcMatch[2];
8865                        var typeMatch = attrs.match(typeRe);
8866                        if(typeMatch && typeMatch[2]){
8867                            s.type = typeMatch[2];
8868                        }
8869                        hd.appendChild(s);
8870                     }else if(match[2] && match[2].length > 0){
8871                         if(window.execScript) {
8872                            window.execScript(match[2]);
8873                         } else {
8874                             /**
8875                              * eval:var:id
8876                              * eval:var:dom
8877                              * eval:var:html
8878                              * 
8879                              */
8880                            window.eval(match[2]);
8881                         }
8882                     }
8883                 }
8884                 var el = document.getElementById(id);
8885                 if(el){el.parentNode.removeChild(el);}
8886                 if(typeof callback == "function"){
8887                     callback();
8888                 }
8889             });
8890             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8891             return this;
8892         },
8893
8894         /**
8895          * Direct access to the UpdateManager update() method (takes the same parameters).
8896          * @param {String/Function} url The url for this request or a function to call to get the url
8897          * @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}
8898          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8899          * @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.
8900          * @return {Roo.Element} this
8901          */
8902         load : function(){
8903             var um = this.getUpdateManager();
8904             um.update.apply(um, arguments);
8905             return this;
8906         },
8907
8908         /**
8909         * Gets this element's UpdateManager
8910         * @return {Roo.UpdateManager} The UpdateManager
8911         */
8912         getUpdateManager : function(){
8913             if(!this.updateManager){
8914                 this.updateManager = new Roo.UpdateManager(this);
8915             }
8916             return this.updateManager;
8917         },
8918
8919         /**
8920          * Disables text selection for this element (normalized across browsers)
8921          * @return {Roo.Element} this
8922          */
8923         unselectable : function(){
8924             this.dom.unselectable = "on";
8925             this.swallowEvent("selectstart", true);
8926             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8927             this.addClass("x-unselectable");
8928             return this;
8929         },
8930
8931         /**
8932         * Calculates the x, y to center this element on the screen
8933         * @return {Array} The x, y values [x, y]
8934         */
8935         getCenterXY : function(){
8936             return this.getAlignToXY(document, 'c-c');
8937         },
8938
8939         /**
8940         * Centers the Element in either the viewport, or another Element.
8941         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8942         */
8943         center : function(centerIn){
8944             this.alignTo(centerIn || document, 'c-c');
8945             return this;
8946         },
8947
8948         /**
8949          * Tests various css rules/browsers to determine if this element uses a border box
8950          * @return {Boolean}
8951          */
8952         isBorderBox : function(){
8953             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8954         },
8955
8956         /**
8957          * Return a box {x, y, width, height} that can be used to set another elements
8958          * size/location to match this element.
8959          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8960          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8961          * @return {Object} box An object in the format {x, y, width, height}
8962          */
8963         getBox : function(contentBox, local){
8964             var xy;
8965             if(!local){
8966                 xy = this.getXY();
8967             }else{
8968                 var left = parseInt(this.getStyle("left"), 10) || 0;
8969                 var top = parseInt(this.getStyle("top"), 10) || 0;
8970                 xy = [left, top];
8971             }
8972             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8973             if(!contentBox){
8974                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8975             }else{
8976                 var l = this.getBorderWidth("l")+this.getPadding("l");
8977                 var r = this.getBorderWidth("r")+this.getPadding("r");
8978                 var t = this.getBorderWidth("t")+this.getPadding("t");
8979                 var b = this.getBorderWidth("b")+this.getPadding("b");
8980                 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)};
8981             }
8982             bx.right = bx.x + bx.width;
8983             bx.bottom = bx.y + bx.height;
8984             return bx;
8985         },
8986
8987         /**
8988          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8989          for more information about the sides.
8990          * @param {String} sides
8991          * @return {Number}
8992          */
8993         getFrameWidth : function(sides, onlyContentBox){
8994             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8995         },
8996
8997         /**
8998          * 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.
8999          * @param {Object} box The box to fill {x, y, width, height}
9000          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9001          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9002          * @return {Roo.Element} this
9003          */
9004         setBox : function(box, adjust, animate){
9005             var w = box.width, h = box.height;
9006             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9007                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9008                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9009             }
9010             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9011             return this;
9012         },
9013
9014         /**
9015          * Forces the browser to repaint this element
9016          * @return {Roo.Element} this
9017          */
9018          repaint : function(){
9019             var dom = this.dom;
9020             this.addClass("x-repaint");
9021             setTimeout(function(){
9022                 Roo.get(dom).removeClass("x-repaint");
9023             }, 1);
9024             return this;
9025         },
9026
9027         /**
9028          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9029          * then it returns the calculated width of the sides (see getPadding)
9030          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9031          * @return {Object/Number}
9032          */
9033         getMargins : function(side){
9034             if(!side){
9035                 return {
9036                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9037                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9038                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9039                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9040                 };
9041             }else{
9042                 return this.addStyles(side, El.margins);
9043              }
9044         },
9045
9046         // private
9047         addStyles : function(sides, styles){
9048             var val = 0, v, w;
9049             for(var i = 0, len = sides.length; i < len; i++){
9050                 v = this.getStyle(styles[sides.charAt(i)]);
9051                 if(v){
9052                      w = parseInt(v, 10);
9053                      if(w){ val += w; }
9054                 }
9055             }
9056             return val;
9057         },
9058
9059         /**
9060          * Creates a proxy element of this element
9061          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9062          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9063          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9064          * @return {Roo.Element} The new proxy element
9065          */
9066         createProxy : function(config, renderTo, matchBox){
9067             if(renderTo){
9068                 renderTo = Roo.getDom(renderTo);
9069             }else{
9070                 renderTo = document.body;
9071             }
9072             config = typeof config == "object" ?
9073                 config : {tag : "div", cls: config};
9074             var proxy = Roo.DomHelper.append(renderTo, config, true);
9075             if(matchBox){
9076                proxy.setBox(this.getBox());
9077             }
9078             return proxy;
9079         },
9080
9081         /**
9082          * Puts a mask over this element to disable user interaction. Requires core.css.
9083          * This method can only be applied to elements which accept child nodes.
9084          * @param {String} msg (optional) A message to display in the mask
9085          * @param {String} msgCls (optional) A css class to apply to the msg element
9086          * @return {Element} The mask  element
9087          */
9088         mask : function(msg, msgCls)
9089         {
9090             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9091                 this.setStyle("position", "relative");
9092             }
9093             if(!this._mask){
9094                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9095             }
9096             this.addClass("x-masked");
9097             this._mask.setDisplayed(true);
9098             
9099             // we wander
9100             var z = 0;
9101             var dom = this.dom;
9102             while (dom && dom.style) {
9103                 if (!isNaN(parseInt(dom.style.zIndex))) {
9104                     z = Math.max(z, parseInt(dom.style.zIndex));
9105                 }
9106                 dom = dom.parentNode;
9107             }
9108             // if we are masking the body - then it hides everything..
9109             if (this.dom == document.body) {
9110                 z = 1000000;
9111                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9112                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9113             }
9114            
9115             if(typeof msg == 'string'){
9116                 if(!this._maskMsg){
9117                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9118                 }
9119                 var mm = this._maskMsg;
9120                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9121                 if (mm.dom.firstChild) { // weird IE issue?
9122                     mm.dom.firstChild.innerHTML = msg;
9123                 }
9124                 mm.setDisplayed(true);
9125                 mm.center(this);
9126                 mm.setStyle('z-index', z + 102);
9127             }
9128             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9129                 this._mask.setHeight(this.getHeight());
9130             }
9131             this._mask.setStyle('z-index', z + 100);
9132             
9133             return this._mask;
9134         },
9135
9136         /**
9137          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9138          * it is cached for reuse.
9139          */
9140         unmask : function(removeEl){
9141             if(this._mask){
9142                 if(removeEl === true){
9143                     this._mask.remove();
9144                     delete this._mask;
9145                     if(this._maskMsg){
9146                         this._maskMsg.remove();
9147                         delete this._maskMsg;
9148                     }
9149                 }else{
9150                     this._mask.setDisplayed(false);
9151                     if(this._maskMsg){
9152                         this._maskMsg.setDisplayed(false);
9153                     }
9154                 }
9155             }
9156             this.removeClass("x-masked");
9157         },
9158
9159         /**
9160          * Returns true if this element is masked
9161          * @return {Boolean}
9162          */
9163         isMasked : function(){
9164             return this._mask && this._mask.isVisible();
9165         },
9166
9167         /**
9168          * Creates an iframe shim for this element to keep selects and other windowed objects from
9169          * showing through.
9170          * @return {Roo.Element} The new shim element
9171          */
9172         createShim : function(){
9173             var el = document.createElement('iframe');
9174             el.frameBorder = 'no';
9175             el.className = 'roo-shim';
9176             if(Roo.isIE && Roo.isSecure){
9177                 el.src = Roo.SSL_SECURE_URL;
9178             }
9179             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9180             shim.autoBoxAdjust = false;
9181             return shim;
9182         },
9183
9184         /**
9185          * Removes this element from the DOM and deletes it from the cache
9186          */
9187         remove : function(){
9188             if(this.dom.parentNode){
9189                 this.dom.parentNode.removeChild(this.dom);
9190             }
9191             delete El.cache[this.dom.id];
9192         },
9193
9194         /**
9195          * Sets up event handlers to add and remove a css class when the mouse is over this element
9196          * @param {String} className
9197          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9198          * mouseout events for children elements
9199          * @return {Roo.Element} this
9200          */
9201         addClassOnOver : function(className, preventFlicker){
9202             this.on("mouseover", function(){
9203                 Roo.fly(this, '_internal').addClass(className);
9204             }, this.dom);
9205             var removeFn = function(e){
9206                 if(preventFlicker !== true || !e.within(this, true)){
9207                     Roo.fly(this, '_internal').removeClass(className);
9208                 }
9209             };
9210             this.on("mouseout", removeFn, this.dom);
9211             return this;
9212         },
9213
9214         /**
9215          * Sets up event handlers to add and remove a css class when this element has the focus
9216          * @param {String} className
9217          * @return {Roo.Element} this
9218          */
9219         addClassOnFocus : function(className){
9220             this.on("focus", function(){
9221                 Roo.fly(this, '_internal').addClass(className);
9222             }, this.dom);
9223             this.on("blur", function(){
9224                 Roo.fly(this, '_internal').removeClass(className);
9225             }, this.dom);
9226             return this;
9227         },
9228         /**
9229          * 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)
9230          * @param {String} className
9231          * @return {Roo.Element} this
9232          */
9233         addClassOnClick : function(className){
9234             var dom = this.dom;
9235             this.on("mousedown", function(){
9236                 Roo.fly(dom, '_internal').addClass(className);
9237                 var d = Roo.get(document);
9238                 var fn = function(){
9239                     Roo.fly(dom, '_internal').removeClass(className);
9240                     d.removeListener("mouseup", fn);
9241                 };
9242                 d.on("mouseup", fn);
9243             });
9244             return this;
9245         },
9246
9247         /**
9248          * Stops the specified event from bubbling and optionally prevents the default action
9249          * @param {String} eventName
9250          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9251          * @return {Roo.Element} this
9252          */
9253         swallowEvent : function(eventName, preventDefault){
9254             var fn = function(e){
9255                 e.stopPropagation();
9256                 if(preventDefault){
9257                     e.preventDefault();
9258                 }
9259             };
9260             if(eventName instanceof Array){
9261                 for(var i = 0, len = eventName.length; i < len; i++){
9262                      this.on(eventName[i], fn);
9263                 }
9264                 return this;
9265             }
9266             this.on(eventName, fn);
9267             return this;
9268         },
9269
9270         /**
9271          * @private
9272          */
9273       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9274
9275         /**
9276          * Sizes this element to its parent element's dimensions performing
9277          * neccessary box adjustments.
9278          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9279          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9280          * @return {Roo.Element} this
9281          */
9282         fitToParent : function(monitorResize, targetParent) {
9283           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9284           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9285           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9286             return;
9287           }
9288           var p = Roo.get(targetParent || this.dom.parentNode);
9289           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9290           if (monitorResize === true) {
9291             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9292             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9293           }
9294           return this;
9295         },
9296
9297         /**
9298          * Gets the next sibling, skipping text nodes
9299          * @return {HTMLElement} The next sibling or null
9300          */
9301         getNextSibling : function(){
9302             var n = this.dom.nextSibling;
9303             while(n && n.nodeType != 1){
9304                 n = n.nextSibling;
9305             }
9306             return n;
9307         },
9308
9309         /**
9310          * Gets the previous sibling, skipping text nodes
9311          * @return {HTMLElement} The previous sibling or null
9312          */
9313         getPrevSibling : function(){
9314             var n = this.dom.previousSibling;
9315             while(n && n.nodeType != 1){
9316                 n = n.previousSibling;
9317             }
9318             return n;
9319         },
9320
9321
9322         /**
9323          * Appends the passed element(s) to this element
9324          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9325          * @return {Roo.Element} this
9326          */
9327         appendChild: function(el){
9328             el = Roo.get(el);
9329             el.appendTo(this);
9330             return this;
9331         },
9332
9333         /**
9334          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9335          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9336          * automatically generated with the specified attributes.
9337          * @param {HTMLElement} insertBefore (optional) a child element of this element
9338          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9339          * @return {Roo.Element} The new child element
9340          */
9341         createChild: function(config, insertBefore, returnDom){
9342             config = config || {tag:'div'};
9343             if(insertBefore){
9344                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9345             }
9346             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9347         },
9348
9349         /**
9350          * Appends this element to the passed element
9351          * @param {String/HTMLElement/Element} el The new parent element
9352          * @return {Roo.Element} this
9353          */
9354         appendTo: function(el){
9355             el = Roo.getDom(el);
9356             el.appendChild(this.dom);
9357             return this;
9358         },
9359
9360         /**
9361          * Inserts this element before the passed element in the DOM
9362          * @param {String/HTMLElement/Element} el The element to insert before
9363          * @return {Roo.Element} this
9364          */
9365         insertBefore: function(el){
9366             el = Roo.getDom(el);
9367             el.parentNode.insertBefore(this.dom, el);
9368             return this;
9369         },
9370
9371         /**
9372          * Inserts this element after the passed element in the DOM
9373          * @param {String/HTMLElement/Element} el The element to insert after
9374          * @return {Roo.Element} this
9375          */
9376         insertAfter: function(el){
9377             el = Roo.getDom(el);
9378             el.parentNode.insertBefore(this.dom, el.nextSibling);
9379             return this;
9380         },
9381
9382         /**
9383          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9384          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385          * @return {Roo.Element} The new child
9386          */
9387         insertFirst: function(el, returnDom){
9388             el = el || {};
9389             if(typeof el == 'object' && !el.nodeType){ // dh config
9390                 return this.createChild(el, this.dom.firstChild, returnDom);
9391             }else{
9392                 el = Roo.getDom(el);
9393                 this.dom.insertBefore(el, this.dom.firstChild);
9394                 return !returnDom ? Roo.get(el) : el;
9395             }
9396         },
9397
9398         /**
9399          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9400          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9401          * @param {String} where (optional) 'before' or 'after' defaults to before
9402          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9403          * @return {Roo.Element} the inserted Element
9404          */
9405         insertSibling: function(el, where, returnDom){
9406             where = where ? where.toLowerCase() : 'before';
9407             el = el || {};
9408             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9409
9410             if(typeof el == 'object' && !el.nodeType){ // dh config
9411                 if(where == 'after' && !this.dom.nextSibling){
9412                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9413                 }else{
9414                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9415                 }
9416
9417             }else{
9418                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9419                             where == 'before' ? this.dom : this.dom.nextSibling);
9420                 if(!returnDom){
9421                     rt = Roo.get(rt);
9422                 }
9423             }
9424             return rt;
9425         },
9426
9427         /**
9428          * Creates and wraps this element with another element
9429          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9430          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9431          * @return {HTMLElement/Element} The newly created wrapper element
9432          */
9433         wrap: function(config, returnDom){
9434             if(!config){
9435                 config = {tag: "div"};
9436             }
9437             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9438             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9439             return newEl;
9440         },
9441
9442         /**
9443          * Replaces the passed element with this element
9444          * @param {String/HTMLElement/Element} el The element to replace
9445          * @return {Roo.Element} this
9446          */
9447         replace: function(el){
9448             el = Roo.get(el);
9449             this.insertBefore(el);
9450             el.remove();
9451             return this;
9452         },
9453
9454         /**
9455          * Inserts an html fragment into this element
9456          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9457          * @param {String} html The HTML fragment
9458          * @param {Boolean} returnEl True to return an Roo.Element
9459          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9460          */
9461         insertHtml : function(where, html, returnEl){
9462             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9463             return returnEl ? Roo.get(el) : el;
9464         },
9465
9466         /**
9467          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9468          * @param {Object} o The object with the attributes
9469          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9470          * @return {Roo.Element} this
9471          */
9472         set : function(o, useSet){
9473             var el = this.dom;
9474             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9475             for(var attr in o){
9476                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9477                 if(attr=="cls"){
9478                     el.className = o["cls"];
9479                 }else{
9480                     if(useSet) {
9481                         el.setAttribute(attr, o[attr]);
9482                     } else {
9483                         el[attr] = o[attr];
9484                     }
9485                 }
9486             }
9487             if(o.style){
9488                 Roo.DomHelper.applyStyles(el, o.style);
9489             }
9490             return this;
9491         },
9492
9493         /**
9494          * Convenience method for constructing a KeyMap
9495          * @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:
9496          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9497          * @param {Function} fn The function to call
9498          * @param {Object} scope (optional) The scope of the function
9499          * @return {Roo.KeyMap} The KeyMap created
9500          */
9501         addKeyListener : function(key, fn, scope){
9502             var config;
9503             if(typeof key != "object" || key instanceof Array){
9504                 config = {
9505                     key: key,
9506                     fn: fn,
9507                     scope: scope
9508                 };
9509             }else{
9510                 config = {
9511                     key : key.key,
9512                     shift : key.shift,
9513                     ctrl : key.ctrl,
9514                     alt : key.alt,
9515                     fn: fn,
9516                     scope: scope
9517                 };
9518             }
9519             return new Roo.KeyMap(this, config);
9520         },
9521
9522         /**
9523          * Creates a KeyMap for this element
9524          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9525          * @return {Roo.KeyMap} The KeyMap created
9526          */
9527         addKeyMap : function(config){
9528             return new Roo.KeyMap(this, config);
9529         },
9530
9531         /**
9532          * Returns true if this element is scrollable.
9533          * @return {Boolean}
9534          */
9535          isScrollable : function(){
9536             var dom = this.dom;
9537             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9538         },
9539
9540         /**
9541          * 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().
9542          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9543          * @param {Number} value The new scroll value
9544          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9545          * @return {Element} this
9546          */
9547
9548         scrollTo : function(side, value, animate){
9549             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9550             if(!animate || !A){
9551                 this.dom[prop] = value;
9552             }else{
9553                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9554                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9555             }
9556             return this;
9557         },
9558
9559         /**
9560          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9561          * within this element's scrollable range.
9562          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9563          * @param {Number} distance How far to scroll the element in pixels
9564          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9565          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9566          * was scrolled as far as it could go.
9567          */
9568          scroll : function(direction, distance, animate){
9569              if(!this.isScrollable()){
9570                  return;
9571              }
9572              var el = this.dom;
9573              var l = el.scrollLeft, t = el.scrollTop;
9574              var w = el.scrollWidth, h = el.scrollHeight;
9575              var cw = el.clientWidth, ch = el.clientHeight;
9576              direction = direction.toLowerCase();
9577              var scrolled = false;
9578              var a = this.preanim(arguments, 2);
9579              switch(direction){
9580                  case "l":
9581                  case "left":
9582                      if(w - l > cw){
9583                          var v = Math.min(l + distance, w-cw);
9584                          this.scrollTo("left", v, a);
9585                          scrolled = true;
9586                      }
9587                      break;
9588                 case "r":
9589                 case "right":
9590                      if(l > 0){
9591                          var v = Math.max(l - distance, 0);
9592                          this.scrollTo("left", v, a);
9593                          scrolled = true;
9594                      }
9595                      break;
9596                 case "t":
9597                 case "top":
9598                 case "up":
9599                      if(t > 0){
9600                          var v = Math.max(t - distance, 0);
9601                          this.scrollTo("top", v, a);
9602                          scrolled = true;
9603                      }
9604                      break;
9605                 case "b":
9606                 case "bottom":
9607                 case "down":
9608                      if(h - t > ch){
9609                          var v = Math.min(t + distance, h-ch);
9610                          this.scrollTo("top", v, a);
9611                          scrolled = true;
9612                      }
9613                      break;
9614              }
9615              return scrolled;
9616         },
9617
9618         /**
9619          * Translates the passed page coordinates into left/top css values for this element
9620          * @param {Number/Array} x The page x or an array containing [x, y]
9621          * @param {Number} y The page y
9622          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9623          */
9624         translatePoints : function(x, y){
9625             if(typeof x == 'object' || x instanceof Array){
9626                 y = x[1]; x = x[0];
9627             }
9628             var p = this.getStyle('position');
9629             var o = this.getXY();
9630
9631             var l = parseInt(this.getStyle('left'), 10);
9632             var t = parseInt(this.getStyle('top'), 10);
9633
9634             if(isNaN(l)){
9635                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9636             }
9637             if(isNaN(t)){
9638                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9639             }
9640
9641             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9642         },
9643
9644         /**
9645          * Returns the current scroll position of the element.
9646          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9647          */
9648         getScroll : function(){
9649             var d = this.dom, doc = document;
9650             if(d == doc || d == doc.body){
9651                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9652                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9653                 return {left: l, top: t};
9654             }else{
9655                 return {left: d.scrollLeft, top: d.scrollTop};
9656             }
9657         },
9658
9659         /**
9660          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9661          * are convert to standard 6 digit hex color.
9662          * @param {String} attr The css attribute
9663          * @param {String} defaultValue The default value to use when a valid color isn't found
9664          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9665          * YUI color anims.
9666          */
9667         getColor : function(attr, defaultValue, prefix){
9668             var v = this.getStyle(attr);
9669             if(!v || v == "transparent" || v == "inherit") {
9670                 return defaultValue;
9671             }
9672             var color = typeof prefix == "undefined" ? "#" : prefix;
9673             if(v.substr(0, 4) == "rgb("){
9674                 var rvs = v.slice(4, v.length -1).split(",");
9675                 for(var i = 0; i < 3; i++){
9676                     var h = parseInt(rvs[i]).toString(16);
9677                     if(h < 16){
9678                         h = "0" + h;
9679                     }
9680                     color += h;
9681                 }
9682             } else {
9683                 if(v.substr(0, 1) == "#"){
9684                     if(v.length == 4) {
9685                         for(var i = 1; i < 4; i++){
9686                             var c = v.charAt(i);
9687                             color +=  c + c;
9688                         }
9689                     }else if(v.length == 7){
9690                         color += v.substr(1);
9691                     }
9692                 }
9693             }
9694             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9695         },
9696
9697         /**
9698          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9699          * gradient background, rounded corners and a 4-way shadow.
9700          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9701          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9702          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9703          * @return {Roo.Element} this
9704          */
9705         boxWrap : function(cls){
9706             cls = cls || 'x-box';
9707             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9708             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9709             return el;
9710         },
9711
9712         /**
9713          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9714          * @param {String} namespace The namespace in which to look for the attribute
9715          * @param {String} name The attribute name
9716          * @return {String} The attribute value
9717          */
9718         getAttributeNS : Roo.isIE ? function(ns, name){
9719             var d = this.dom;
9720             var type = typeof d[ns+":"+name];
9721             if(type != 'undefined' && type != 'unknown'){
9722                 return d[ns+":"+name];
9723             }
9724             return d[name];
9725         } : function(ns, name){
9726             var d = this.dom;
9727             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9728         },
9729         
9730         
9731         /**
9732          * Sets or Returns the value the dom attribute value
9733          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9734          * @param {String} value (optional) The value to set the attribute to
9735          * @return {String} The attribute value
9736          */
9737         attr : function(name){
9738             if (arguments.length > 1) {
9739                 this.dom.setAttribute(name, arguments[1]);
9740                 return arguments[1];
9741             }
9742             if (typeof(name) == 'object') {
9743                 for(var i in name) {
9744                     this.attr(i, name[i]);
9745                 }
9746                 return name;
9747             }
9748             
9749             
9750             if (!this.dom.hasAttribute(name)) {
9751                 return undefined;
9752             }
9753             return this.dom.getAttribute(name);
9754         }
9755         
9756         
9757         
9758     };
9759
9760     var ep = El.prototype;
9761
9762     /**
9763      * Appends an event handler (Shorthand for addListener)
9764      * @param {String}   eventName     The type of event to append
9765      * @param {Function} fn        The method the event invokes
9766      * @param {Object} scope       (optional) The scope (this object) of the fn
9767      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9768      * @method
9769      */
9770     ep.on = ep.addListener;
9771         // backwards compat
9772     ep.mon = ep.addListener;
9773
9774     /**
9775      * Removes an event handler from this element (shorthand for removeListener)
9776      * @param {String} eventName the type of event to remove
9777      * @param {Function} fn the method the event invokes
9778      * @return {Roo.Element} this
9779      * @method
9780      */
9781     ep.un = ep.removeListener;
9782
9783     /**
9784      * true to automatically adjust width and height settings for box-model issues (default to true)
9785      */
9786     ep.autoBoxAdjust = true;
9787
9788     // private
9789     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9790
9791     // private
9792     El.addUnits = function(v, defaultUnit){
9793         if(v === "" || v == "auto"){
9794             return v;
9795         }
9796         if(v === undefined){
9797             return '';
9798         }
9799         if(typeof v == "number" || !El.unitPattern.test(v)){
9800             return v + (defaultUnit || 'px');
9801         }
9802         return v;
9803     };
9804
9805     // special markup used throughout Roo when box wrapping elements
9806     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>';
9807     /**
9808      * Visibility mode constant - Use visibility to hide element
9809      * @static
9810      * @type Number
9811      */
9812     El.VISIBILITY = 1;
9813     /**
9814      * Visibility mode constant - Use display to hide element
9815      * @static
9816      * @type Number
9817      */
9818     El.DISPLAY = 2;
9819
9820     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9821     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9822     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9823
9824
9825
9826     /**
9827      * @private
9828      */
9829     El.cache = {};
9830
9831     var docEl;
9832
9833     /**
9834      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9835      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9836      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9837      * @return {Element} The Element object
9838      * @static
9839      */
9840     El.get = function(el){
9841         var ex, elm, id;
9842         if(!el){ return null; }
9843         if(typeof el == "string"){ // element id
9844             if(!(elm = document.getElementById(el))){
9845                 return null;
9846             }
9847             if(ex = El.cache[el]){
9848                 ex.dom = elm;
9849             }else{
9850                 ex = El.cache[el] = new El(elm);
9851             }
9852             return ex;
9853         }else if(el.tagName){ // dom element
9854             if(!(id = el.id)){
9855                 id = Roo.id(el);
9856             }
9857             if(ex = El.cache[id]){
9858                 ex.dom = el;
9859             }else{
9860                 ex = El.cache[id] = new El(el);
9861             }
9862             return ex;
9863         }else if(el instanceof El){
9864             if(el != docEl){
9865                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9866                                                               // catch case where it hasn't been appended
9867                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9868             }
9869             return el;
9870         }else if(el.isComposite){
9871             return el;
9872         }else if(el instanceof Array){
9873             return El.select(el);
9874         }else if(el == document){
9875             // create a bogus element object representing the document object
9876             if(!docEl){
9877                 var f = function(){};
9878                 f.prototype = El.prototype;
9879                 docEl = new f();
9880                 docEl.dom = document;
9881             }
9882             return docEl;
9883         }
9884         return null;
9885     };
9886
9887     // private
9888     El.uncache = function(el){
9889         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9890             if(a[i]){
9891                 delete El.cache[a[i].id || a[i]];
9892             }
9893         }
9894     };
9895
9896     // private
9897     // Garbage collection - uncache elements/purge listeners on orphaned elements
9898     // so we don't hold a reference and cause the browser to retain them
9899     El.garbageCollect = function(){
9900         if(!Roo.enableGarbageCollector){
9901             clearInterval(El.collectorThread);
9902             return;
9903         }
9904         for(var eid in El.cache){
9905             var el = El.cache[eid], d = el.dom;
9906             // -------------------------------------------------------
9907             // Determining what is garbage:
9908             // -------------------------------------------------------
9909             // !d
9910             // dom node is null, definitely garbage
9911             // -------------------------------------------------------
9912             // !d.parentNode
9913             // no parentNode == direct orphan, definitely garbage
9914             // -------------------------------------------------------
9915             // !d.offsetParent && !document.getElementById(eid)
9916             // display none elements have no offsetParent so we will
9917             // also try to look it up by it's id. However, check
9918             // offsetParent first so we don't do unneeded lookups.
9919             // This enables collection of elements that are not orphans
9920             // directly, but somewhere up the line they have an orphan
9921             // parent.
9922             // -------------------------------------------------------
9923             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9924                 delete El.cache[eid];
9925                 if(d && Roo.enableListenerCollection){
9926                     E.purgeElement(d);
9927                 }
9928             }
9929         }
9930     }
9931     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9932
9933
9934     // dom is optional
9935     El.Flyweight = function(dom){
9936         this.dom = dom;
9937     };
9938     El.Flyweight.prototype = El.prototype;
9939
9940     El._flyweights = {};
9941     /**
9942      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9943      * the dom node can be overwritten by other code.
9944      * @param {String/HTMLElement} el The dom node or id
9945      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9946      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9947      * @static
9948      * @return {Element} The shared Element object
9949      */
9950     El.fly = function(el, named){
9951         named = named || '_global';
9952         el = Roo.getDom(el);
9953         if(!el){
9954             return null;
9955         }
9956         if(!El._flyweights[named]){
9957             El._flyweights[named] = new El.Flyweight();
9958         }
9959         El._flyweights[named].dom = el;
9960         return El._flyweights[named];
9961     };
9962
9963     /**
9964      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9965      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9966      * Shorthand of {@link Roo.Element#get}
9967      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9968      * @return {Element} The Element object
9969      * @member Roo
9970      * @method get
9971      */
9972     Roo.get = El.get;
9973     /**
9974      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9975      * the dom node can be overwritten by other code.
9976      * Shorthand of {@link Roo.Element#fly}
9977      * @param {String/HTMLElement} el The dom node or id
9978      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9979      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9980      * @static
9981      * @return {Element} The shared Element object
9982      * @member Roo
9983      * @method fly
9984      */
9985     Roo.fly = El.fly;
9986
9987     // speedy lookup for elements never to box adjust
9988     var noBoxAdjust = Roo.isStrict ? {
9989         select:1
9990     } : {
9991         input:1, select:1, textarea:1
9992     };
9993     if(Roo.isIE || Roo.isGecko){
9994         noBoxAdjust['button'] = 1;
9995     }
9996
9997
9998     Roo.EventManager.on(window, 'unload', function(){
9999         delete El.cache;
10000         delete El._flyweights;
10001     });
10002 })();
10003
10004
10005
10006
10007 if(Roo.DomQuery){
10008     Roo.Element.selectorFunction = Roo.DomQuery.select;
10009 }
10010
10011 Roo.Element.select = function(selector, unique, root){
10012     var els;
10013     if(typeof selector == "string"){
10014         els = Roo.Element.selectorFunction(selector, root);
10015     }else if(selector.length !== undefined){
10016         els = selector;
10017     }else{
10018         throw "Invalid selector";
10019     }
10020     if(unique === true){
10021         return new Roo.CompositeElement(els);
10022     }else{
10023         return new Roo.CompositeElementLite(els);
10024     }
10025 };
10026 /**
10027  * Selects elements based on the passed CSS selector to enable working on them as 1.
10028  * @param {String/Array} selector The CSS selector or an array of elements
10029  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10030  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10031  * @return {CompositeElementLite/CompositeElement}
10032  * @member Roo
10033  * @method select
10034  */
10035 Roo.select = Roo.Element.select;
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050 /*
10051  * Based on:
10052  * Ext JS Library 1.1.1
10053  * Copyright(c) 2006-2007, Ext JS, LLC.
10054  *
10055  * Originally Released Under LGPL - original licence link has changed is not relivant.
10056  *
10057  * Fork - LGPL
10058  * <script type="text/javascript">
10059  */
10060
10061
10062
10063 //Notifies Element that fx methods are available
10064 Roo.enableFx = true;
10065
10066 /**
10067  * @class Roo.Fx
10068  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10069  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10070  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10071  * Element effects to work.</p><br/>
10072  *
10073  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10074  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10075  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10076  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10077  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10078  * expected results and should be done with care.</p><br/>
10079  *
10080  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10081  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10082 <pre>
10083 Value  Description
10084 -----  -----------------------------
10085 tl     The top left corner
10086 t      The center of the top edge
10087 tr     The top right corner
10088 l      The center of the left edge
10089 r      The center of the right edge
10090 bl     The bottom left corner
10091 b      The center of the bottom edge
10092 br     The bottom right corner
10093 </pre>
10094  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10095  * below are common options that can be passed to any Fx method.</b>
10096  * @cfg {Function} callback A function called when the effect is finished
10097  * @cfg {Object} scope The scope of the effect function
10098  * @cfg {String} easing A valid Easing value for the effect
10099  * @cfg {String} afterCls A css class to apply after the effect
10100  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10101  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10102  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10103  * effects that end with the element being visually hidden, ignored otherwise)
10104  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10105  * a function which returns such a specification that will be applied to the Element after the effect finishes
10106  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10107  * @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
10108  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10109  */
10110 Roo.Fx = {
10111         /**
10112          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10113          * origin for the slide effect.  This function automatically handles wrapping the element with
10114          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10115          * Usage:
10116          *<pre><code>
10117 // default: slide the element in from the top
10118 el.slideIn();
10119
10120 // custom: slide the element in from the right with a 2-second duration
10121 el.slideIn('r', { duration: 2 });
10122
10123 // common config options shown with default values
10124 el.slideIn('t', {
10125     easing: 'easeOut',
10126     duration: .5
10127 });
10128 </code></pre>
10129          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10130          * @param {Object} options (optional) Object literal with any of the Fx config options
10131          * @return {Roo.Element} The Element
10132          */
10133     slideIn : function(anchor, o){
10134         var el = this.getFxEl();
10135         o = o || {};
10136
10137         el.queueFx(o, function(){
10138
10139             anchor = anchor || "t";
10140
10141             // fix display to visibility
10142             this.fixDisplay();
10143
10144             // restore values after effect
10145             var r = this.getFxRestore();
10146             var b = this.getBox();
10147             // fixed size for slide
10148             this.setSize(b);
10149
10150             // wrap if needed
10151             var wrap = this.fxWrap(r.pos, o, "hidden");
10152
10153             var st = this.dom.style;
10154             st.visibility = "visible";
10155             st.position = "absolute";
10156
10157             // clear out temp styles after slide and unwrap
10158             var after = function(){
10159                 el.fxUnwrap(wrap, r.pos, o);
10160                 st.width = r.width;
10161                 st.height = r.height;
10162                 el.afterFx(o);
10163             };
10164             // time to calc the positions
10165             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10166
10167             switch(anchor.toLowerCase()){
10168                 case "t":
10169                     wrap.setSize(b.width, 0);
10170                     st.left = st.bottom = "0";
10171                     a = {height: bh};
10172                 break;
10173                 case "l":
10174                     wrap.setSize(0, b.height);
10175                     st.right = st.top = "0";
10176                     a = {width: bw};
10177                 break;
10178                 case "r":
10179                     wrap.setSize(0, b.height);
10180                     wrap.setX(b.right);
10181                     st.left = st.top = "0";
10182                     a = {width: bw, points: pt};
10183                 break;
10184                 case "b":
10185                     wrap.setSize(b.width, 0);
10186                     wrap.setY(b.bottom);
10187                     st.left = st.top = "0";
10188                     a = {height: bh, points: pt};
10189                 break;
10190                 case "tl":
10191                     wrap.setSize(0, 0);
10192                     st.right = st.bottom = "0";
10193                     a = {width: bw, height: bh};
10194                 break;
10195                 case "bl":
10196                     wrap.setSize(0, 0);
10197                     wrap.setY(b.y+b.height);
10198                     st.right = st.top = "0";
10199                     a = {width: bw, height: bh, points: pt};
10200                 break;
10201                 case "br":
10202                     wrap.setSize(0, 0);
10203                     wrap.setXY([b.right, b.bottom]);
10204                     st.left = st.top = "0";
10205                     a = {width: bw, height: bh, points: pt};
10206                 break;
10207                 case "tr":
10208                     wrap.setSize(0, 0);
10209                     wrap.setX(b.x+b.width);
10210                     st.left = st.bottom = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213             }
10214             this.dom.style.visibility = "visible";
10215             wrap.show();
10216
10217             arguments.callee.anim = wrap.fxanim(a,
10218                 o,
10219                 'motion',
10220                 .5,
10221                 'easeOut', after);
10222         });
10223         return this;
10224     },
10225     
10226         /**
10227          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10228          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10229          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10230          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10231          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10232          * Usage:
10233          *<pre><code>
10234 // default: slide the element out to the top
10235 el.slideOut();
10236
10237 // custom: slide the element out to the right with a 2-second duration
10238 el.slideOut('r', { duration: 2 });
10239
10240 // common config options shown with default values
10241 el.slideOut('t', {
10242     easing: 'easeOut',
10243     duration: .5,
10244     remove: false,
10245     useDisplay: false
10246 });
10247 </code></pre>
10248          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10249          * @param {Object} options (optional) Object literal with any of the Fx config options
10250          * @return {Roo.Element} The Element
10251          */
10252     slideOut : function(anchor, o){
10253         var el = this.getFxEl();
10254         o = o || {};
10255
10256         el.queueFx(o, function(){
10257
10258             anchor = anchor || "t";
10259
10260             // restore values after effect
10261             var r = this.getFxRestore();
10262             
10263             var b = this.getBox();
10264             // fixed size for slide
10265             this.setSize(b);
10266
10267             // wrap if needed
10268             var wrap = this.fxWrap(r.pos, o, "visible");
10269
10270             var st = this.dom.style;
10271             st.visibility = "visible";
10272             st.position = "absolute";
10273
10274             wrap.setSize(b);
10275
10276             var after = function(){
10277                 if(o.useDisplay){
10278                     el.setDisplayed(false);
10279                 }else{
10280                     el.hide();
10281                 }
10282
10283                 el.fxUnwrap(wrap, r.pos, o);
10284
10285                 st.width = r.width;
10286                 st.height = r.height;
10287
10288                 el.afterFx(o);
10289             };
10290
10291             var a, zero = {to: 0};
10292             switch(anchor.toLowerCase()){
10293                 case "t":
10294                     st.left = st.bottom = "0";
10295                     a = {height: zero};
10296                 break;
10297                 case "l":
10298                     st.right = st.top = "0";
10299                     a = {width: zero};
10300                 break;
10301                 case "r":
10302                     st.left = st.top = "0";
10303                     a = {width: zero, points: {to:[b.right, b.y]}};
10304                 break;
10305                 case "b":
10306                     st.left = st.top = "0";
10307                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10308                 break;
10309                 case "tl":
10310                     st.right = st.bottom = "0";
10311                     a = {width: zero, height: zero};
10312                 break;
10313                 case "bl":
10314                     st.right = st.top = "0";
10315                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10316                 break;
10317                 case "br":
10318                     st.left = st.top = "0";
10319                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10320                 break;
10321                 case "tr":
10322                     st.left = st.bottom = "0";
10323                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10324                 break;
10325             }
10326
10327             arguments.callee.anim = wrap.fxanim(a,
10328                 o,
10329                 'motion',
10330                 .5,
10331                 "easeOut", after);
10332         });
10333         return this;
10334     },
10335
10336         /**
10337          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10338          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10339          * The element must be removed from the DOM using the 'remove' config option if desired.
10340          * Usage:
10341          *<pre><code>
10342 // default
10343 el.puff();
10344
10345 // common config options shown with default values
10346 el.puff({
10347     easing: 'easeOut',
10348     duration: .5,
10349     remove: false,
10350     useDisplay: false
10351 });
10352 </code></pre>
10353          * @param {Object} options (optional) Object literal with any of the Fx config options
10354          * @return {Roo.Element} The Element
10355          */
10356     puff : function(o){
10357         var el = this.getFxEl();
10358         o = o || {};
10359
10360         el.queueFx(o, function(){
10361             this.clearOpacity();
10362             this.show();
10363
10364             // restore values after effect
10365             var r = this.getFxRestore();
10366             var st = this.dom.style;
10367
10368             var after = function(){
10369                 if(o.useDisplay){
10370                     el.setDisplayed(false);
10371                 }else{
10372                     el.hide();
10373                 }
10374
10375                 el.clearOpacity();
10376
10377                 el.setPositioning(r.pos);
10378                 st.width = r.width;
10379                 st.height = r.height;
10380                 st.fontSize = '';
10381                 el.afterFx(o);
10382             };
10383
10384             var width = this.getWidth();
10385             var height = this.getHeight();
10386
10387             arguments.callee.anim = this.fxanim({
10388                     width : {to: this.adjustWidth(width * 2)},
10389                     height : {to: this.adjustHeight(height * 2)},
10390                     points : {by: [-(width * .5), -(height * .5)]},
10391                     opacity : {to: 0},
10392                     fontSize: {to:200, unit: "%"}
10393                 },
10394                 o,
10395                 'motion',
10396                 .5,
10397                 "easeOut", after);
10398         });
10399         return this;
10400     },
10401
10402         /**
10403          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10404          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10405          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10406          * Usage:
10407          *<pre><code>
10408 // default
10409 el.switchOff();
10410
10411 // all config options shown with default values
10412 el.switchOff({
10413     easing: 'easeIn',
10414     duration: .3,
10415     remove: false,
10416     useDisplay: false
10417 });
10418 </code></pre>
10419          * @param {Object} options (optional) Object literal with any of the Fx config options
10420          * @return {Roo.Element} The Element
10421          */
10422     switchOff : function(o){
10423         var el = this.getFxEl();
10424         o = o || {};
10425
10426         el.queueFx(o, function(){
10427             this.clearOpacity();
10428             this.clip();
10429
10430             // restore values after effect
10431             var r = this.getFxRestore();
10432             var st = this.dom.style;
10433
10434             var after = function(){
10435                 if(o.useDisplay){
10436                     el.setDisplayed(false);
10437                 }else{
10438                     el.hide();
10439                 }
10440
10441                 el.clearOpacity();
10442                 el.setPositioning(r.pos);
10443                 st.width = r.width;
10444                 st.height = r.height;
10445
10446                 el.afterFx(o);
10447             };
10448
10449             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10450                 this.clearOpacity();
10451                 (function(){
10452                     this.fxanim({
10453                         height:{to:1},
10454                         points:{by:[0, this.getHeight() * .5]}
10455                     }, o, 'motion', 0.3, 'easeIn', after);
10456                 }).defer(100, this);
10457             });
10458         });
10459         return this;
10460     },
10461
10462     /**
10463      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10464      * changed using the "attr" config option) and then fading back to the original color. If no original
10465      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10466      * Usage:
10467 <pre><code>
10468 // default: highlight background to yellow
10469 el.highlight();
10470
10471 // custom: highlight foreground text to blue for 2 seconds
10472 el.highlight("0000ff", { attr: 'color', duration: 2 });
10473
10474 // common config options shown with default values
10475 el.highlight("ffff9c", {
10476     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10477     endColor: (current color) or "ffffff",
10478     easing: 'easeIn',
10479     duration: 1
10480 });
10481 </code></pre>
10482      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10483      * @param {Object} options (optional) Object literal with any of the Fx config options
10484      * @return {Roo.Element} The Element
10485      */ 
10486     highlight : function(color, o){
10487         var el = this.getFxEl();
10488         o = o || {};
10489
10490         el.queueFx(o, function(){
10491             color = color || "ffff9c";
10492             attr = o.attr || "backgroundColor";
10493
10494             this.clearOpacity();
10495             this.show();
10496
10497             var origColor = this.getColor(attr);
10498             var restoreColor = this.dom.style[attr];
10499             endColor = (o.endColor || origColor) || "ffffff";
10500
10501             var after = function(){
10502                 el.dom.style[attr] = restoreColor;
10503                 el.afterFx(o);
10504             };
10505
10506             var a = {};
10507             a[attr] = {from: color, to: endColor};
10508             arguments.callee.anim = this.fxanim(a,
10509                 o,
10510                 'color',
10511                 1,
10512                 'easeIn', after);
10513         });
10514         return this;
10515     },
10516
10517    /**
10518     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10519     * Usage:
10520 <pre><code>
10521 // default: a single light blue ripple
10522 el.frame();
10523
10524 // custom: 3 red ripples lasting 3 seconds total
10525 el.frame("ff0000", 3, { duration: 3 });
10526
10527 // common config options shown with default values
10528 el.frame("C3DAF9", 1, {
10529     duration: 1 //duration of entire animation (not each individual ripple)
10530     // Note: Easing is not configurable and will be ignored if included
10531 });
10532 </code></pre>
10533     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10534     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10535     * @param {Object} options (optional) Object literal with any of the Fx config options
10536     * @return {Roo.Element} The Element
10537     */
10538     frame : function(color, count, o){
10539         var el = this.getFxEl();
10540         o = o || {};
10541
10542         el.queueFx(o, function(){
10543             color = color || "#C3DAF9";
10544             if(color.length == 6){
10545                 color = "#" + color;
10546             }
10547             count = count || 1;
10548             duration = o.duration || 1;
10549             this.show();
10550
10551             var b = this.getBox();
10552             var animFn = function(){
10553                 var proxy = this.createProxy({
10554
10555                      style:{
10556                         visbility:"hidden",
10557                         position:"absolute",
10558                         "z-index":"35000", // yee haw
10559                         border:"0px solid " + color
10560                      }
10561                   });
10562                 var scale = Roo.isBorderBox ? 2 : 1;
10563                 proxy.animate({
10564                     top:{from:b.y, to:b.y - 20},
10565                     left:{from:b.x, to:b.x - 20},
10566                     borderWidth:{from:0, to:10},
10567                     opacity:{from:1, to:0},
10568                     height:{from:b.height, to:(b.height + (20*scale))},
10569                     width:{from:b.width, to:(b.width + (20*scale))}
10570                 }, duration, function(){
10571                     proxy.remove();
10572                 });
10573                 if(--count > 0){
10574                      animFn.defer((duration/2)*1000, this);
10575                 }else{
10576                     el.afterFx(o);
10577                 }
10578             };
10579             animFn.call(this);
10580         });
10581         return this;
10582     },
10583
10584    /**
10585     * Creates a pause before any subsequent queued effects begin.  If there are
10586     * no effects queued after the pause it will have no effect.
10587     * Usage:
10588 <pre><code>
10589 el.pause(1);
10590 </code></pre>
10591     * @param {Number} seconds The length of time to pause (in seconds)
10592     * @return {Roo.Element} The Element
10593     */
10594     pause : function(seconds){
10595         var el = this.getFxEl();
10596         var o = {};
10597
10598         el.queueFx(o, function(){
10599             setTimeout(function(){
10600                 el.afterFx(o);
10601             }, seconds * 1000);
10602         });
10603         return this;
10604     },
10605
10606    /**
10607     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10608     * using the "endOpacity" config option.
10609     * Usage:
10610 <pre><code>
10611 // default: fade in from opacity 0 to 100%
10612 el.fadeIn();
10613
10614 // custom: fade in from opacity 0 to 75% over 2 seconds
10615 el.fadeIn({ endOpacity: .75, duration: 2});
10616
10617 // common config options shown with default values
10618 el.fadeIn({
10619     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10620     easing: 'easeOut',
10621     duration: .5
10622 });
10623 </code></pre>
10624     * @param {Object} options (optional) Object literal with any of the Fx config options
10625     * @return {Roo.Element} The Element
10626     */
10627     fadeIn : function(o){
10628         var el = this.getFxEl();
10629         o = o || {};
10630         el.queueFx(o, function(){
10631             this.setOpacity(0);
10632             this.fixDisplay();
10633             this.dom.style.visibility = 'visible';
10634             var to = o.endOpacity || 1;
10635             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10636                 o, null, .5, "easeOut", function(){
10637                 if(to == 1){
10638                     this.clearOpacity();
10639                 }
10640                 el.afterFx(o);
10641             });
10642         });
10643         return this;
10644     },
10645
10646    /**
10647     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10648     * using the "endOpacity" config option.
10649     * Usage:
10650 <pre><code>
10651 // default: fade out from the element's current opacity to 0
10652 el.fadeOut();
10653
10654 // custom: fade out from the element's current opacity to 25% over 2 seconds
10655 el.fadeOut({ endOpacity: .25, duration: 2});
10656
10657 // common config options shown with default values
10658 el.fadeOut({
10659     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10660     easing: 'easeOut',
10661     duration: .5
10662     remove: false,
10663     useDisplay: false
10664 });
10665 </code></pre>
10666     * @param {Object} options (optional) Object literal with any of the Fx config options
10667     * @return {Roo.Element} The Element
10668     */
10669     fadeOut : function(o){
10670         var el = this.getFxEl();
10671         o = o || {};
10672         el.queueFx(o, function(){
10673             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10674                 o, null, .5, "easeOut", function(){
10675                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10676                      this.dom.style.display = "none";
10677                 }else{
10678                      this.dom.style.visibility = "hidden";
10679                 }
10680                 this.clearOpacity();
10681                 el.afterFx(o);
10682             });
10683         });
10684         return this;
10685     },
10686
10687    /**
10688     * Animates the transition of an element's dimensions from a starting height/width
10689     * to an ending height/width.
10690     * Usage:
10691 <pre><code>
10692 // change height and width to 100x100 pixels
10693 el.scale(100, 100);
10694
10695 // common config options shown with default values.  The height and width will default to
10696 // the element's existing values if passed as null.
10697 el.scale(
10698     [element's width],
10699     [element's height], {
10700     easing: 'easeOut',
10701     duration: .35
10702 });
10703 </code></pre>
10704     * @param {Number} width  The new width (pass undefined to keep the original width)
10705     * @param {Number} height  The new height (pass undefined to keep the original height)
10706     * @param {Object} options (optional) Object literal with any of the Fx config options
10707     * @return {Roo.Element} The Element
10708     */
10709     scale : function(w, h, o){
10710         this.shift(Roo.apply({}, o, {
10711             width: w,
10712             height: h
10713         }));
10714         return this;
10715     },
10716
10717    /**
10718     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10719     * Any of these properties not specified in the config object will not be changed.  This effect 
10720     * requires that at least one new dimension, position or opacity setting must be passed in on
10721     * the config object in order for the function to have any effect.
10722     * Usage:
10723 <pre><code>
10724 // slide the element horizontally to x position 200 while changing the height and opacity
10725 el.shift({ x: 200, height: 50, opacity: .8 });
10726
10727 // common config options shown with default values.
10728 el.shift({
10729     width: [element's width],
10730     height: [element's height],
10731     x: [element's x position],
10732     y: [element's y position],
10733     opacity: [element's opacity],
10734     easing: 'easeOut',
10735     duration: .35
10736 });
10737 </code></pre>
10738     * @param {Object} options  Object literal with any of the Fx config options
10739     * @return {Roo.Element} The Element
10740     */
10741     shift : function(o){
10742         var el = this.getFxEl();
10743         o = o || {};
10744         el.queueFx(o, function(){
10745             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10746             if(w !== undefined){
10747                 a.width = {to: this.adjustWidth(w)};
10748             }
10749             if(h !== undefined){
10750                 a.height = {to: this.adjustHeight(h)};
10751             }
10752             if(x !== undefined || y !== undefined){
10753                 a.points = {to: [
10754                     x !== undefined ? x : this.getX(),
10755                     y !== undefined ? y : this.getY()
10756                 ]};
10757             }
10758             if(op !== undefined){
10759                 a.opacity = {to: op};
10760             }
10761             if(o.xy !== undefined){
10762                 a.points = {to: o.xy};
10763             }
10764             arguments.callee.anim = this.fxanim(a,
10765                 o, 'motion', .35, "easeOut", function(){
10766                 el.afterFx(o);
10767             });
10768         });
10769         return this;
10770     },
10771
10772         /**
10773          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10774          * ending point of the effect.
10775          * Usage:
10776          *<pre><code>
10777 // default: slide the element downward while fading out
10778 el.ghost();
10779
10780 // custom: slide the element out to the right with a 2-second duration
10781 el.ghost('r', { duration: 2 });
10782
10783 // common config options shown with default values
10784 el.ghost('b', {
10785     easing: 'easeOut',
10786     duration: .5
10787     remove: false,
10788     useDisplay: false
10789 });
10790 </code></pre>
10791          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10792          * @param {Object} options (optional) Object literal with any of the Fx config options
10793          * @return {Roo.Element} The Element
10794          */
10795     ghost : function(anchor, o){
10796         var el = this.getFxEl();
10797         o = o || {};
10798
10799         el.queueFx(o, function(){
10800             anchor = anchor || "b";
10801
10802             // restore values after effect
10803             var r = this.getFxRestore();
10804             var w = this.getWidth(),
10805                 h = this.getHeight();
10806
10807             var st = this.dom.style;
10808
10809             var after = function(){
10810                 if(o.useDisplay){
10811                     el.setDisplayed(false);
10812                 }else{
10813                     el.hide();
10814                 }
10815
10816                 el.clearOpacity();
10817                 el.setPositioning(r.pos);
10818                 st.width = r.width;
10819                 st.height = r.height;
10820
10821                 el.afterFx(o);
10822             };
10823
10824             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10825             switch(anchor.toLowerCase()){
10826                 case "t":
10827                     pt.by = [0, -h];
10828                 break;
10829                 case "l":
10830                     pt.by = [-w, 0];
10831                 break;
10832                 case "r":
10833                     pt.by = [w, 0];
10834                 break;
10835                 case "b":
10836                     pt.by = [0, h];
10837                 break;
10838                 case "tl":
10839                     pt.by = [-w, -h];
10840                 break;
10841                 case "bl":
10842                     pt.by = [-w, h];
10843                 break;
10844                 case "br":
10845                     pt.by = [w, h];
10846                 break;
10847                 case "tr":
10848                     pt.by = [w, -h];
10849                 break;
10850             }
10851
10852             arguments.callee.anim = this.fxanim(a,
10853                 o,
10854                 'motion',
10855                 .5,
10856                 "easeOut", after);
10857         });
10858         return this;
10859     },
10860
10861         /**
10862          * Ensures that all effects queued after syncFx is called on the element are
10863          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10864          * @return {Roo.Element} The Element
10865          */
10866     syncFx : function(){
10867         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10868             block : false,
10869             concurrent : true,
10870             stopFx : false
10871         });
10872         return this;
10873     },
10874
10875         /**
10876          * Ensures that all effects queued after sequenceFx is called on the element are
10877          * run in sequence.  This is the opposite of {@link #syncFx}.
10878          * @return {Roo.Element} The Element
10879          */
10880     sequenceFx : function(){
10881         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10882             block : false,
10883             concurrent : false,
10884             stopFx : false
10885         });
10886         return this;
10887     },
10888
10889         /* @private */
10890     nextFx : function(){
10891         var ef = this.fxQueue[0];
10892         if(ef){
10893             ef.call(this);
10894         }
10895     },
10896
10897         /**
10898          * Returns true if the element has any effects actively running or queued, else returns false.
10899          * @return {Boolean} True if element has active effects, else false
10900          */
10901     hasActiveFx : function(){
10902         return this.fxQueue && this.fxQueue[0];
10903     },
10904
10905         /**
10906          * Stops any running effects and clears the element's internal effects queue if it contains
10907          * any additional effects that haven't started yet.
10908          * @return {Roo.Element} The Element
10909          */
10910     stopFx : function(){
10911         if(this.hasActiveFx()){
10912             var cur = this.fxQueue[0];
10913             if(cur && cur.anim && cur.anim.isAnimated()){
10914                 this.fxQueue = [cur]; // clear out others
10915                 cur.anim.stop(true);
10916             }
10917         }
10918         return this;
10919     },
10920
10921         /* @private */
10922     beforeFx : function(o){
10923         if(this.hasActiveFx() && !o.concurrent){
10924            if(o.stopFx){
10925                this.stopFx();
10926                return true;
10927            }
10928            return false;
10929         }
10930         return true;
10931     },
10932
10933         /**
10934          * Returns true if the element is currently blocking so that no other effect can be queued
10935          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10936          * used to ensure that an effect initiated by a user action runs to completion prior to the
10937          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10938          * @return {Boolean} True if blocking, else false
10939          */
10940     hasFxBlock : function(){
10941         var q = this.fxQueue;
10942         return q && q[0] && q[0].block;
10943     },
10944
10945         /* @private */
10946     queueFx : function(o, fn){
10947         if(!this.fxQueue){
10948             this.fxQueue = [];
10949         }
10950         if(!this.hasFxBlock()){
10951             Roo.applyIf(o, this.fxDefaults);
10952             if(!o.concurrent){
10953                 var run = this.beforeFx(o);
10954                 fn.block = o.block;
10955                 this.fxQueue.push(fn);
10956                 if(run){
10957                     this.nextFx();
10958                 }
10959             }else{
10960                 fn.call(this);
10961             }
10962         }
10963         return this;
10964     },
10965
10966         /* @private */
10967     fxWrap : function(pos, o, vis){
10968         var wrap;
10969         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10970             var wrapXY;
10971             if(o.fixPosition){
10972                 wrapXY = this.getXY();
10973             }
10974             var div = document.createElement("div");
10975             div.style.visibility = vis;
10976             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10977             wrap.setPositioning(pos);
10978             if(wrap.getStyle("position") == "static"){
10979                 wrap.position("relative");
10980             }
10981             this.clearPositioning('auto');
10982             wrap.clip();
10983             wrap.dom.appendChild(this.dom);
10984             if(wrapXY){
10985                 wrap.setXY(wrapXY);
10986             }
10987         }
10988         return wrap;
10989     },
10990
10991         /* @private */
10992     fxUnwrap : function(wrap, pos, o){
10993         this.clearPositioning();
10994         this.setPositioning(pos);
10995         if(!o.wrap){
10996             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10997             wrap.remove();
10998         }
10999     },
11000
11001         /* @private */
11002     getFxRestore : function(){
11003         var st = this.dom.style;
11004         return {pos: this.getPositioning(), width: st.width, height : st.height};
11005     },
11006
11007         /* @private */
11008     afterFx : function(o){
11009         if(o.afterStyle){
11010             this.applyStyles(o.afterStyle);
11011         }
11012         if(o.afterCls){
11013             this.addClass(o.afterCls);
11014         }
11015         if(o.remove === true){
11016             this.remove();
11017         }
11018         Roo.callback(o.callback, o.scope, [this]);
11019         if(!o.concurrent){
11020             this.fxQueue.shift();
11021             this.nextFx();
11022         }
11023     },
11024
11025         /* @private */
11026     getFxEl : function(){ // support for composite element fx
11027         return Roo.get(this.dom);
11028     },
11029
11030         /* @private */
11031     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11032         animType = animType || 'run';
11033         opt = opt || {};
11034         var anim = Roo.lib.Anim[animType](
11035             this.dom, args,
11036             (opt.duration || defaultDur) || .35,
11037             (opt.easing || defaultEase) || 'easeOut',
11038             function(){
11039                 Roo.callback(cb, this);
11040             },
11041             this
11042         );
11043         opt.anim = anim;
11044         return anim;
11045     }
11046 };
11047
11048 // backwords compat
11049 Roo.Fx.resize = Roo.Fx.scale;
11050
11051 //When included, Roo.Fx is automatically applied to Element so that all basic
11052 //effects are available directly via the Element API
11053 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11054  * Based on:
11055  * Ext JS Library 1.1.1
11056  * Copyright(c) 2006-2007, Ext JS, LLC.
11057  *
11058  * Originally Released Under LGPL - original licence link has changed is not relivant.
11059  *
11060  * Fork - LGPL
11061  * <script type="text/javascript">
11062  */
11063
11064
11065 /**
11066  * @class Roo.CompositeElement
11067  * Standard composite class. Creates a Roo.Element for every element in the collection.
11068  * <br><br>
11069  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11070  * actions will be performed on all the elements in this collection.</b>
11071  * <br><br>
11072  * All methods return <i>this</i> and can be chained.
11073  <pre><code>
11074  var els = Roo.select("#some-el div.some-class", true);
11075  // or select directly from an existing element
11076  var el = Roo.get('some-el');
11077  el.select('div.some-class', true);
11078
11079  els.setWidth(100); // all elements become 100 width
11080  els.hide(true); // all elements fade out and hide
11081  // or
11082  els.setWidth(100).hide(true);
11083  </code></pre>
11084  */
11085 Roo.CompositeElement = function(els){
11086     this.elements = [];
11087     this.addElements(els);
11088 };
11089 Roo.CompositeElement.prototype = {
11090     isComposite: true,
11091     addElements : function(els){
11092         if(!els) {
11093             return this;
11094         }
11095         if(typeof els == "string"){
11096             els = Roo.Element.selectorFunction(els);
11097         }
11098         var yels = this.elements;
11099         var index = yels.length-1;
11100         for(var i = 0, len = els.length; i < len; i++) {
11101                 yels[++index] = Roo.get(els[i]);
11102         }
11103         return this;
11104     },
11105
11106     /**
11107     * Clears this composite and adds the elements returned by the passed selector.
11108     * @param {String/Array} els A string CSS selector, an array of elements or an element
11109     * @return {CompositeElement} this
11110     */
11111     fill : function(els){
11112         this.elements = [];
11113         this.add(els);
11114         return this;
11115     },
11116
11117     /**
11118     * Filters this composite to only elements that match the passed selector.
11119     * @param {String} selector A string CSS selector
11120     * @param {Boolean} inverse return inverse filter (not matches)
11121     * @return {CompositeElement} this
11122     */
11123     filter : function(selector, inverse){
11124         var els = [];
11125         inverse = inverse || false;
11126         this.each(function(el){
11127             var match = inverse ? !el.is(selector) : el.is(selector);
11128             if(match){
11129                 els[els.length] = el.dom;
11130             }
11131         });
11132         this.fill(els);
11133         return this;
11134     },
11135
11136     invoke : function(fn, args){
11137         var els = this.elements;
11138         for(var i = 0, len = els.length; i < len; i++) {
11139                 Roo.Element.prototype[fn].apply(els[i], args);
11140         }
11141         return this;
11142     },
11143     /**
11144     * Adds elements to this composite.
11145     * @param {String/Array} els A string CSS selector, an array of elements or an element
11146     * @return {CompositeElement} this
11147     */
11148     add : function(els){
11149         if(typeof els == "string"){
11150             this.addElements(Roo.Element.selectorFunction(els));
11151         }else if(els.length !== undefined){
11152             this.addElements(els);
11153         }else{
11154             this.addElements([els]);
11155         }
11156         return this;
11157     },
11158     /**
11159     * Calls the passed function passing (el, this, index) for each element in this composite.
11160     * @param {Function} fn The function to call
11161     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11162     * @return {CompositeElement} this
11163     */
11164     each : function(fn, scope){
11165         var els = this.elements;
11166         for(var i = 0, len = els.length; i < len; i++){
11167             if(fn.call(scope || els[i], els[i], this, i) === false) {
11168                 break;
11169             }
11170         }
11171         return this;
11172     },
11173
11174     /**
11175      * Returns the Element object at the specified index
11176      * @param {Number} index
11177      * @return {Roo.Element}
11178      */
11179     item : function(index){
11180         return this.elements[index] || null;
11181     },
11182
11183     /**
11184      * Returns the first Element
11185      * @return {Roo.Element}
11186      */
11187     first : function(){
11188         return this.item(0);
11189     },
11190
11191     /**
11192      * Returns the last Element
11193      * @return {Roo.Element}
11194      */
11195     last : function(){
11196         return this.item(this.elements.length-1);
11197     },
11198
11199     /**
11200      * Returns the number of elements in this composite
11201      * @return Number
11202      */
11203     getCount : function(){
11204         return this.elements.length;
11205     },
11206
11207     /**
11208      * Returns true if this composite contains the passed element
11209      * @return Boolean
11210      */
11211     contains : function(el){
11212         return this.indexOf(el) !== -1;
11213     },
11214
11215     /**
11216      * Returns true if this composite contains the passed element
11217      * @return Boolean
11218      */
11219     indexOf : function(el){
11220         return this.elements.indexOf(Roo.get(el));
11221     },
11222
11223
11224     /**
11225     * Removes the specified element(s).
11226     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11227     * or an array of any of those.
11228     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11229     * @return {CompositeElement} this
11230     */
11231     removeElement : function(el, removeDom){
11232         if(el instanceof Array){
11233             for(var i = 0, len = el.length; i < len; i++){
11234                 this.removeElement(el[i]);
11235             }
11236             return this;
11237         }
11238         var index = typeof el == 'number' ? el : this.indexOf(el);
11239         if(index !== -1){
11240             if(removeDom){
11241                 var d = this.elements[index];
11242                 if(d.dom){
11243                     d.remove();
11244                 }else{
11245                     d.parentNode.removeChild(d);
11246                 }
11247             }
11248             this.elements.splice(index, 1);
11249         }
11250         return this;
11251     },
11252
11253     /**
11254     * Replaces the specified element with the passed element.
11255     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11256     * to replace.
11257     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11258     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11259     * @return {CompositeElement} this
11260     */
11261     replaceElement : function(el, replacement, domReplace){
11262         var index = typeof el == 'number' ? el : this.indexOf(el);
11263         if(index !== -1){
11264             if(domReplace){
11265                 this.elements[index].replaceWith(replacement);
11266             }else{
11267                 this.elements.splice(index, 1, Roo.get(replacement))
11268             }
11269         }
11270         return this;
11271     },
11272
11273     /**
11274      * Removes all elements.
11275      */
11276     clear : function(){
11277         this.elements = [];
11278     }
11279 };
11280 (function(){
11281     Roo.CompositeElement.createCall = function(proto, fnName){
11282         if(!proto[fnName]){
11283             proto[fnName] = function(){
11284                 return this.invoke(fnName, arguments);
11285             };
11286         }
11287     };
11288     for(var fnName in Roo.Element.prototype){
11289         if(typeof Roo.Element.prototype[fnName] == "function"){
11290             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11291         }
11292     };
11293 })();
11294 /*
11295  * Based on:
11296  * Ext JS Library 1.1.1
11297  * Copyright(c) 2006-2007, Ext JS, LLC.
11298  *
11299  * Originally Released Under LGPL - original licence link has changed is not relivant.
11300  *
11301  * Fork - LGPL
11302  * <script type="text/javascript">
11303  */
11304
11305 /**
11306  * @class Roo.CompositeElementLite
11307  * @extends Roo.CompositeElement
11308  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11309  <pre><code>
11310  var els = Roo.select("#some-el div.some-class");
11311  // or select directly from an existing element
11312  var el = Roo.get('some-el');
11313  el.select('div.some-class');
11314
11315  els.setWidth(100); // all elements become 100 width
11316  els.hide(true); // all elements fade out and hide
11317  // or
11318  els.setWidth(100).hide(true);
11319  </code></pre><br><br>
11320  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11321  * actions will be performed on all the elements in this collection.</b>
11322  */
11323 Roo.CompositeElementLite = function(els){
11324     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11325     this.el = new Roo.Element.Flyweight();
11326 };
11327 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11328     addElements : function(els){
11329         if(els){
11330             if(els instanceof Array){
11331                 this.elements = this.elements.concat(els);
11332             }else{
11333                 var yels = this.elements;
11334                 var index = yels.length-1;
11335                 for(var i = 0, len = els.length; i < len; i++) {
11336                     yels[++index] = els[i];
11337                 }
11338             }
11339         }
11340         return this;
11341     },
11342     invoke : function(fn, args){
11343         var els = this.elements;
11344         var el = this.el;
11345         for(var i = 0, len = els.length; i < len; i++) {
11346             el.dom = els[i];
11347                 Roo.Element.prototype[fn].apply(el, args);
11348         }
11349         return this;
11350     },
11351     /**
11352      * Returns a flyweight Element of the dom element object at the specified index
11353      * @param {Number} index
11354      * @return {Roo.Element}
11355      */
11356     item : function(index){
11357         if(!this.elements[index]){
11358             return null;
11359         }
11360         this.el.dom = this.elements[index];
11361         return this.el;
11362     },
11363
11364     // fixes scope with flyweight
11365     addListener : function(eventName, handler, scope, opt){
11366         var els = this.elements;
11367         for(var i = 0, len = els.length; i < len; i++) {
11368             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11369         }
11370         return this;
11371     },
11372
11373     /**
11374     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11375     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11376     * a reference to the dom node, use el.dom.</b>
11377     * @param {Function} fn The function to call
11378     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11379     * @return {CompositeElement} this
11380     */
11381     each : function(fn, scope){
11382         var els = this.elements;
11383         var el = this.el;
11384         for(var i = 0, len = els.length; i < len; i++){
11385             el.dom = els[i];
11386                 if(fn.call(scope || el, el, this, i) === false){
11387                 break;
11388             }
11389         }
11390         return this;
11391     },
11392
11393     indexOf : function(el){
11394         return this.elements.indexOf(Roo.getDom(el));
11395     },
11396
11397     replaceElement : function(el, replacement, domReplace){
11398         var index = typeof el == 'number' ? el : this.indexOf(el);
11399         if(index !== -1){
11400             replacement = Roo.getDom(replacement);
11401             if(domReplace){
11402                 var d = this.elements[index];
11403                 d.parentNode.insertBefore(replacement, d);
11404                 d.parentNode.removeChild(d);
11405             }
11406             this.elements.splice(index, 1, replacement);
11407         }
11408         return this;
11409     }
11410 });
11411 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11412
11413 /*
11414  * Based on:
11415  * Ext JS Library 1.1.1
11416  * Copyright(c) 2006-2007, Ext JS, LLC.
11417  *
11418  * Originally Released Under LGPL - original licence link has changed is not relivant.
11419  *
11420  * Fork - LGPL
11421  * <script type="text/javascript">
11422  */
11423
11424  
11425
11426 /**
11427  * @class Roo.data.Connection
11428  * @extends Roo.util.Observable
11429  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11430  * either to a configured URL, or to a URL specified at request time.<br><br>
11431  * <p>
11432  * Requests made by this class are asynchronous, and will return immediately. No data from
11433  * the server will be available to the statement immediately following the {@link #request} call.
11434  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11435  * <p>
11436  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11437  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11438  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11439  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11440  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11441  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11442  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11443  * standard DOM methods.
11444  * @constructor
11445  * @param {Object} config a configuration object.
11446  */
11447 Roo.data.Connection = function(config){
11448     Roo.apply(this, config);
11449     this.addEvents({
11450         /**
11451          * @event beforerequest
11452          * Fires before a network request is made to retrieve a data object.
11453          * @param {Connection} conn This Connection object.
11454          * @param {Object} options The options config object passed to the {@link #request} method.
11455          */
11456         "beforerequest" : true,
11457         /**
11458          * @event requestcomplete
11459          * Fires if the request was successfully completed.
11460          * @param {Connection} conn This Connection object.
11461          * @param {Object} response The XHR object containing the response data.
11462          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11463          * @param {Object} options The options config object passed to the {@link #request} method.
11464          */
11465         "requestcomplete" : true,
11466         /**
11467          * @event requestexception
11468          * Fires if an error HTTP status was returned from the server.
11469          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11470          * @param {Connection} conn This Connection object.
11471          * @param {Object} response The XHR object containing the response data.
11472          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11473          * @param {Object} options The options config object passed to the {@link #request} method.
11474          */
11475         "requestexception" : true
11476     });
11477     Roo.data.Connection.superclass.constructor.call(this);
11478 };
11479
11480 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11481     /**
11482      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11483      */
11484     /**
11485      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11486      * extra parameters to each request made by this object. (defaults to undefined)
11487      */
11488     /**
11489      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11490      *  to each request made by this object. (defaults to undefined)
11491      */
11492     /**
11493      * @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)
11494      */
11495     /**
11496      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11497      */
11498     timeout : 30000,
11499     /**
11500      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11501      * @type Boolean
11502      */
11503     autoAbort:false,
11504
11505     /**
11506      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11507      * @type Boolean
11508      */
11509     disableCaching: true,
11510
11511     /**
11512      * Sends an HTTP request to a remote server.
11513      * @param {Object} options An object which may contain the following properties:<ul>
11514      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11515      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11516      * request, a url encoded string or a function to call to get either.</li>
11517      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11518      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11519      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11520      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11521      * <li>options {Object} The parameter to the request call.</li>
11522      * <li>success {Boolean} True if the request succeeded.</li>
11523      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11524      * </ul></li>
11525      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11526      * The callback is passed the following parameters:<ul>
11527      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11528      * <li>options {Object} The parameter to the request call.</li>
11529      * </ul></li>
11530      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11531      * The callback is passed the following parameters:<ul>
11532      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11533      * <li>options {Object} The parameter to the request call.</li>
11534      * </ul></li>
11535      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11536      * for the callback function. Defaults to the browser window.</li>
11537      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11538      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11539      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11540      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11541      * params for the post data. Any params will be appended to the URL.</li>
11542      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11543      * </ul>
11544      * @return {Number} transactionId
11545      */
11546     request : function(o){
11547         if(this.fireEvent("beforerequest", this, o) !== false){
11548             var p = o.params;
11549
11550             if(typeof p == "function"){
11551                 p = p.call(o.scope||window, o);
11552             }
11553             if(typeof p == "object"){
11554                 p = Roo.urlEncode(o.params);
11555             }
11556             if(this.extraParams){
11557                 var extras = Roo.urlEncode(this.extraParams);
11558                 p = p ? (p + '&' + extras) : extras;
11559             }
11560
11561             var url = o.url || this.url;
11562             if(typeof url == 'function'){
11563                 url = url.call(o.scope||window, o);
11564             }
11565
11566             if(o.form){
11567                 var form = Roo.getDom(o.form);
11568                 url = url || form.action;
11569
11570                 var enctype = form.getAttribute("enctype");
11571                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11572                     return this.doFormUpload(o, p, url);
11573                 }
11574                 var f = Roo.lib.Ajax.serializeForm(form);
11575                 p = p ? (p + '&' + f) : f;
11576             }
11577
11578             var hs = o.headers;
11579             if(this.defaultHeaders){
11580                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11581                 if(!o.headers){
11582                     o.headers = hs;
11583                 }
11584             }
11585
11586             var cb = {
11587                 success: this.handleResponse,
11588                 failure: this.handleFailure,
11589                 scope: this,
11590                 argument: {options: o},
11591                 timeout : o.timeout || this.timeout
11592             };
11593
11594             var method = o.method||this.method||(p ? "POST" : "GET");
11595
11596             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11597                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11598             }
11599
11600             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11601                 if(o.autoAbort){
11602                     this.abort();
11603                 }
11604             }else if(this.autoAbort !== false){
11605                 this.abort();
11606             }
11607
11608             if((method == 'GET' && p) || o.xmlData){
11609                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11610                 p = '';
11611             }
11612             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11613             return this.transId;
11614         }else{
11615             Roo.callback(o.callback, o.scope, [o, null, null]);
11616             return null;
11617         }
11618     },
11619
11620     /**
11621      * Determine whether this object has a request outstanding.
11622      * @param {Number} transactionId (Optional) defaults to the last transaction
11623      * @return {Boolean} True if there is an outstanding request.
11624      */
11625     isLoading : function(transId){
11626         if(transId){
11627             return Roo.lib.Ajax.isCallInProgress(transId);
11628         }else{
11629             return this.transId ? true : false;
11630         }
11631     },
11632
11633     /**
11634      * Aborts any outstanding request.
11635      * @param {Number} transactionId (Optional) defaults to the last transaction
11636      */
11637     abort : function(transId){
11638         if(transId || this.isLoading()){
11639             Roo.lib.Ajax.abort(transId || this.transId);
11640         }
11641     },
11642
11643     // private
11644     handleResponse : function(response){
11645         this.transId = false;
11646         var options = response.argument.options;
11647         response.argument = options ? options.argument : null;
11648         this.fireEvent("requestcomplete", this, response, options);
11649         Roo.callback(options.success, options.scope, [response, options]);
11650         Roo.callback(options.callback, options.scope, [options, true, response]);
11651     },
11652
11653     // private
11654     handleFailure : function(response, e){
11655         this.transId = false;
11656         var options = response.argument.options;
11657         response.argument = options ? options.argument : null;
11658         this.fireEvent("requestexception", this, response, options, e);
11659         Roo.callback(options.failure, options.scope, [response, options]);
11660         Roo.callback(options.callback, options.scope, [options, false, response]);
11661     },
11662
11663     // private
11664     doFormUpload : function(o, ps, url){
11665         var id = Roo.id();
11666         var frame = document.createElement('iframe');
11667         frame.id = id;
11668         frame.name = id;
11669         frame.className = 'x-hidden';
11670         if(Roo.isIE){
11671             frame.src = Roo.SSL_SECURE_URL;
11672         }
11673         document.body.appendChild(frame);
11674
11675         if(Roo.isIE){
11676            document.frames[id].name = id;
11677         }
11678
11679         var form = Roo.getDom(o.form);
11680         form.target = id;
11681         form.method = 'POST';
11682         form.enctype = form.encoding = 'multipart/form-data';
11683         if(url){
11684             form.action = url;
11685         }
11686
11687         var hiddens, hd;
11688         if(ps){ // add dynamic params
11689             hiddens = [];
11690             ps = Roo.urlDecode(ps, false);
11691             for(var k in ps){
11692                 if(ps.hasOwnProperty(k)){
11693                     hd = document.createElement('input');
11694                     hd.type = 'hidden';
11695                     hd.name = k;
11696                     hd.value = ps[k];
11697                     form.appendChild(hd);
11698                     hiddens.push(hd);
11699                 }
11700             }
11701         }
11702
11703         function cb(){
11704             var r = {  // bogus response object
11705                 responseText : '',
11706                 responseXML : null
11707             };
11708
11709             r.argument = o ? o.argument : null;
11710
11711             try { //
11712                 var doc;
11713                 if(Roo.isIE){
11714                     doc = frame.contentWindow.document;
11715                 }else {
11716                     doc = (frame.contentDocument || window.frames[id].document);
11717                 }
11718                 if(doc && doc.body){
11719                     r.responseText = doc.body.innerHTML;
11720                 }
11721                 if(doc && doc.XMLDocument){
11722                     r.responseXML = doc.XMLDocument;
11723                 }else {
11724                     r.responseXML = doc;
11725                 }
11726             }
11727             catch(e) {
11728                 // ignore
11729             }
11730
11731             Roo.EventManager.removeListener(frame, 'load', cb, this);
11732
11733             this.fireEvent("requestcomplete", this, r, o);
11734             Roo.callback(o.success, o.scope, [r, o]);
11735             Roo.callback(o.callback, o.scope, [o, true, r]);
11736
11737             setTimeout(function(){document.body.removeChild(frame);}, 100);
11738         }
11739
11740         Roo.EventManager.on(frame, 'load', cb, this);
11741         form.submit();
11742
11743         if(hiddens){ // remove dynamic params
11744             for(var i = 0, len = hiddens.length; i < len; i++){
11745                 form.removeChild(hiddens[i]);
11746             }
11747         }
11748     }
11749 });
11750 /*
11751  * Based on:
11752  * Ext JS Library 1.1.1
11753  * Copyright(c) 2006-2007, Ext JS, LLC.
11754  *
11755  * Originally Released Under LGPL - original licence link has changed is not relivant.
11756  *
11757  * Fork - LGPL
11758  * <script type="text/javascript">
11759  */
11760  
11761 /**
11762  * Global Ajax request class.
11763  * 
11764  * @class Roo.Ajax
11765  * @extends Roo.data.Connection
11766  * @static
11767  * 
11768  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11769  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11770  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11771  * @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)
11772  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11773  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11774  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11775  */
11776 Roo.Ajax = new Roo.data.Connection({
11777     // fix up the docs
11778     /**
11779      * @scope Roo.Ajax
11780      * @type {Boolear} 
11781      */
11782     autoAbort : false,
11783
11784     /**
11785      * Serialize the passed form into a url encoded string
11786      * @scope Roo.Ajax
11787      * @param {String/HTMLElement} form
11788      * @return {String}
11789      */
11790     serializeForm : function(form){
11791         return Roo.lib.Ajax.serializeForm(form);
11792     }
11793 });/*
11794  * Based on:
11795  * Ext JS Library 1.1.1
11796  * Copyright(c) 2006-2007, Ext JS, LLC.
11797  *
11798  * Originally Released Under LGPL - original licence link has changed is not relivant.
11799  *
11800  * Fork - LGPL
11801  * <script type="text/javascript">
11802  */
11803
11804  
11805 /**
11806  * @class Roo.UpdateManager
11807  * @extends Roo.util.Observable
11808  * Provides AJAX-style update for Element object.<br><br>
11809  * Usage:<br>
11810  * <pre><code>
11811  * // Get it from a Roo.Element object
11812  * var el = Roo.get("foo");
11813  * var mgr = el.getUpdateManager();
11814  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11815  * ...
11816  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11817  * <br>
11818  * // or directly (returns the same UpdateManager instance)
11819  * var mgr = new Roo.UpdateManager("myElementId");
11820  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11821  * mgr.on("update", myFcnNeedsToKnow);
11822  * <br>
11823    // short handed call directly from the element object
11824    Roo.get("foo").load({
11825         url: "bar.php",
11826         scripts:true,
11827         params: "for=bar",
11828         text: "Loading Foo..."
11829    });
11830  * </code></pre>
11831  * @constructor
11832  * Create new UpdateManager directly.
11833  * @param {String/HTMLElement/Roo.Element} el The element to update
11834  * @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).
11835  */
11836 Roo.UpdateManager = function(el, forceNew){
11837     el = Roo.get(el);
11838     if(!forceNew && el.updateManager){
11839         return el.updateManager;
11840     }
11841     /**
11842      * The Element object
11843      * @type Roo.Element
11844      */
11845     this.el = el;
11846     /**
11847      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11848      * @type String
11849      */
11850     this.defaultUrl = null;
11851
11852     this.addEvents({
11853         /**
11854          * @event beforeupdate
11855          * Fired before an update is made, return false from your handler and the update is cancelled.
11856          * @param {Roo.Element} el
11857          * @param {String/Object/Function} url
11858          * @param {String/Object} params
11859          */
11860         "beforeupdate": true,
11861         /**
11862          * @event update
11863          * Fired after successful update is made.
11864          * @param {Roo.Element} el
11865          * @param {Object} oResponseObject The response Object
11866          */
11867         "update": true,
11868         /**
11869          * @event failure
11870          * Fired on update failure.
11871          * @param {Roo.Element} el
11872          * @param {Object} oResponseObject The response Object
11873          */
11874         "failure": true
11875     });
11876     var d = Roo.UpdateManager.defaults;
11877     /**
11878      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11879      * @type String
11880      */
11881     this.sslBlankUrl = d.sslBlankUrl;
11882     /**
11883      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11884      * @type Boolean
11885      */
11886     this.disableCaching = d.disableCaching;
11887     /**
11888      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11889      * @type String
11890      */
11891     this.indicatorText = d.indicatorText;
11892     /**
11893      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11894      * @type String
11895      */
11896     this.showLoadIndicator = d.showLoadIndicator;
11897     /**
11898      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11899      * @type Number
11900      */
11901     this.timeout = d.timeout;
11902
11903     /**
11904      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11905      * @type Boolean
11906      */
11907     this.loadScripts = d.loadScripts;
11908
11909     /**
11910      * Transaction object of current executing transaction
11911      */
11912     this.transaction = null;
11913
11914     /**
11915      * @private
11916      */
11917     this.autoRefreshProcId = null;
11918     /**
11919      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11920      * @type Function
11921      */
11922     this.refreshDelegate = this.refresh.createDelegate(this);
11923     /**
11924      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11925      * @type Function
11926      */
11927     this.updateDelegate = this.update.createDelegate(this);
11928     /**
11929      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11930      * @type Function
11931      */
11932     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11933     /**
11934      * @private
11935      */
11936     this.successDelegate = this.processSuccess.createDelegate(this);
11937     /**
11938      * @private
11939      */
11940     this.failureDelegate = this.processFailure.createDelegate(this);
11941
11942     if(!this.renderer){
11943      /**
11944       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11945       */
11946     this.renderer = new Roo.UpdateManager.BasicRenderer();
11947     }
11948     
11949     Roo.UpdateManager.superclass.constructor.call(this);
11950 };
11951
11952 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11953     /**
11954      * Get the Element this UpdateManager is bound to
11955      * @return {Roo.Element} The element
11956      */
11957     getEl : function(){
11958         return this.el;
11959     },
11960     /**
11961      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11962      * @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:
11963 <pre><code>
11964 um.update({<br/>
11965     url: "your-url.php",<br/>
11966     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11967     callback: yourFunction,<br/>
11968     scope: yourObject, //(optional scope)  <br/>
11969     discardUrl: false, <br/>
11970     nocache: false,<br/>
11971     text: "Loading...",<br/>
11972     timeout: 30,<br/>
11973     scripts: false<br/>
11974 });
11975 </code></pre>
11976      * The only required property is url. The optional properties nocache, text and scripts
11977      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11978      * @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}
11979      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11980      * @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.
11981      */
11982     update : function(url, params, callback, discardUrl){
11983         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11984             var method = this.method,
11985                 cfg;
11986             if(typeof url == "object"){ // must be config object
11987                 cfg = url;
11988                 url = cfg.url;
11989                 params = params || cfg.params;
11990                 callback = callback || cfg.callback;
11991                 discardUrl = discardUrl || cfg.discardUrl;
11992                 if(callback && cfg.scope){
11993                     callback = callback.createDelegate(cfg.scope);
11994                 }
11995                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11996                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11997                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11998                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11999                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12000             }
12001             this.showLoading();
12002             if(!discardUrl){
12003                 this.defaultUrl = url;
12004             }
12005             if(typeof url == "function"){
12006                 url = url.call(this);
12007             }
12008
12009             method = method || (params ? "POST" : "GET");
12010             if(method == "GET"){
12011                 url = this.prepareUrl(url);
12012             }
12013
12014             var o = Roo.apply(cfg ||{}, {
12015                 url : url,
12016                 params: params,
12017                 success: this.successDelegate,
12018                 failure: this.failureDelegate,
12019                 callback: undefined,
12020                 timeout: (this.timeout*1000),
12021                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12022             });
12023             Roo.log("updated manager called with timeout of " + o.timeout);
12024             this.transaction = Roo.Ajax.request(o);
12025         }
12026     },
12027
12028     /**
12029      * 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.
12030      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12031      * @param {String/HTMLElement} form The form Id or form element
12032      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12033      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12034      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12035      */
12036     formUpdate : function(form, url, reset, callback){
12037         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12038             if(typeof url == "function"){
12039                 url = url.call(this);
12040             }
12041             form = Roo.getDom(form);
12042             this.transaction = Roo.Ajax.request({
12043                 form: form,
12044                 url:url,
12045                 success: this.successDelegate,
12046                 failure: this.failureDelegate,
12047                 timeout: (this.timeout*1000),
12048                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12049             });
12050             this.showLoading.defer(1, this);
12051         }
12052     },
12053
12054     /**
12055      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12056      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12057      */
12058     refresh : function(callback){
12059         if(this.defaultUrl == null){
12060             return;
12061         }
12062         this.update(this.defaultUrl, null, callback, true);
12063     },
12064
12065     /**
12066      * Set this element to auto refresh.
12067      * @param {Number} interval How often to update (in seconds).
12068      * @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)
12069      * @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}
12070      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12071      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12072      */
12073     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12074         if(refreshNow){
12075             this.update(url || this.defaultUrl, params, callback, true);
12076         }
12077         if(this.autoRefreshProcId){
12078             clearInterval(this.autoRefreshProcId);
12079         }
12080         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12081     },
12082
12083     /**
12084      * Stop auto refresh on this element.
12085      */
12086      stopAutoRefresh : function(){
12087         if(this.autoRefreshProcId){
12088             clearInterval(this.autoRefreshProcId);
12089             delete this.autoRefreshProcId;
12090         }
12091     },
12092
12093     isAutoRefreshing : function(){
12094        return this.autoRefreshProcId ? true : false;
12095     },
12096     /**
12097      * Called to update the element to "Loading" state. Override to perform custom action.
12098      */
12099     showLoading : function(){
12100         if(this.showLoadIndicator){
12101             this.el.update(this.indicatorText);
12102         }
12103     },
12104
12105     /**
12106      * Adds unique parameter to query string if disableCaching = true
12107      * @private
12108      */
12109     prepareUrl : function(url){
12110         if(this.disableCaching){
12111             var append = "_dc=" + (new Date().getTime());
12112             if(url.indexOf("?") !== -1){
12113                 url += "&" + append;
12114             }else{
12115                 url += "?" + append;
12116             }
12117         }
12118         return url;
12119     },
12120
12121     /**
12122      * @private
12123      */
12124     processSuccess : function(response){
12125         this.transaction = null;
12126         if(response.argument.form && response.argument.reset){
12127             try{ // put in try/catch since some older FF releases had problems with this
12128                 response.argument.form.reset();
12129             }catch(e){}
12130         }
12131         if(this.loadScripts){
12132             this.renderer.render(this.el, response, this,
12133                 this.updateComplete.createDelegate(this, [response]));
12134         }else{
12135             this.renderer.render(this.el, response, this);
12136             this.updateComplete(response);
12137         }
12138     },
12139
12140     updateComplete : function(response){
12141         this.fireEvent("update", this.el, response);
12142         if(typeof response.argument.callback == "function"){
12143             response.argument.callback(this.el, true, response);
12144         }
12145     },
12146
12147     /**
12148      * @private
12149      */
12150     processFailure : function(response){
12151         this.transaction = null;
12152         this.fireEvent("failure", this.el, response);
12153         if(typeof response.argument.callback == "function"){
12154             response.argument.callback(this.el, false, response);
12155         }
12156     },
12157
12158     /**
12159      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12160      * @param {Object} renderer The object implementing the render() method
12161      */
12162     setRenderer : function(renderer){
12163         this.renderer = renderer;
12164     },
12165
12166     getRenderer : function(){
12167        return this.renderer;
12168     },
12169
12170     /**
12171      * Set the defaultUrl used for updates
12172      * @param {String/Function} defaultUrl The url or a function to call to get the url
12173      */
12174     setDefaultUrl : function(defaultUrl){
12175         this.defaultUrl = defaultUrl;
12176     },
12177
12178     /**
12179      * Aborts the executing transaction
12180      */
12181     abort : function(){
12182         if(this.transaction){
12183             Roo.Ajax.abort(this.transaction);
12184         }
12185     },
12186
12187     /**
12188      * Returns true if an update is in progress
12189      * @return {Boolean}
12190      */
12191     isUpdating : function(){
12192         if(this.transaction){
12193             return Roo.Ajax.isLoading(this.transaction);
12194         }
12195         return false;
12196     }
12197 });
12198
12199 /**
12200  * @class Roo.UpdateManager.defaults
12201  * @static (not really - but it helps the doc tool)
12202  * The defaults collection enables customizing the default properties of UpdateManager
12203  */
12204    Roo.UpdateManager.defaults = {
12205        /**
12206          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12207          * @type Number
12208          */
12209          timeout : 30,
12210
12211          /**
12212          * True to process scripts by default (Defaults to false).
12213          * @type Boolean
12214          */
12215         loadScripts : false,
12216
12217         /**
12218         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12219         * @type String
12220         */
12221         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12222         /**
12223          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12224          * @type Boolean
12225          */
12226         disableCaching : false,
12227         /**
12228          * Whether to show indicatorText when loading (Defaults to true).
12229          * @type Boolean
12230          */
12231         showLoadIndicator : true,
12232         /**
12233          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12234          * @type String
12235          */
12236         indicatorText : '<div class="loading-indicator">Loading...</div>'
12237    };
12238
12239 /**
12240  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12241  *Usage:
12242  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12243  * @param {String/HTMLElement/Roo.Element} el The element to update
12244  * @param {String} url The url
12245  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12246  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12247  * @static
12248  * @deprecated
12249  * @member Roo.UpdateManager
12250  */
12251 Roo.UpdateManager.updateElement = function(el, url, params, options){
12252     var um = Roo.get(el, true).getUpdateManager();
12253     Roo.apply(um, options);
12254     um.update(url, params, options ? options.callback : null);
12255 };
12256 // alias for backwards compat
12257 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12258 /**
12259  * @class Roo.UpdateManager.BasicRenderer
12260  * Default Content renderer. Updates the elements innerHTML with the responseText.
12261  */
12262 Roo.UpdateManager.BasicRenderer = function(){};
12263
12264 Roo.UpdateManager.BasicRenderer.prototype = {
12265     /**
12266      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12267      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12268      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12269      * @param {Roo.Element} el The element being rendered
12270      * @param {Object} response The YUI Connect response object
12271      * @param {UpdateManager} updateManager The calling update manager
12272      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12273      */
12274      render : function(el, response, updateManager, callback){
12275         el.update(response.responseText, updateManager.loadScripts, callback);
12276     }
12277 };
12278 /*
12279  * Based on:
12280  * Roo JS
12281  * (c)) Alan Knowles
12282  * Licence : LGPL
12283  */
12284
12285
12286 /**
12287  * @class Roo.DomTemplate
12288  * @extends Roo.Template
12289  * An effort at a dom based template engine..
12290  *
12291  * Similar to XTemplate, except it uses dom parsing to create the template..
12292  *
12293  * Supported features:
12294  *
12295  *  Tags:
12296
12297 <pre><code>
12298       {a_variable} - output encoded.
12299       {a_variable.format:("Y-m-d")} - call a method on the variable
12300       {a_variable:raw} - unencoded output
12301       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12302       {a_variable:this.method_on_template(...)} - call a method on the template object.
12303  
12304 </code></pre>
12305  *  The tpl tag:
12306 <pre><code>
12307         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12308         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12309         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12310         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12311   
12312 </code></pre>
12313  *      
12314  */
12315 Roo.DomTemplate = function()
12316 {
12317      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12318      if (this.html) {
12319         this.compile();
12320      }
12321 };
12322
12323
12324 Roo.extend(Roo.DomTemplate, Roo.Template, {
12325     /**
12326      * id counter for sub templates.
12327      */
12328     id : 0,
12329     /**
12330      * flag to indicate if dom parser is inside a pre,
12331      * it will strip whitespace if not.
12332      */
12333     inPre : false,
12334     
12335     /**
12336      * The various sub templates
12337      */
12338     tpls : false,
12339     
12340     
12341     
12342     /**
12343      *
12344      * basic tag replacing syntax
12345      * WORD:WORD()
12346      *
12347      * // you can fake an object call by doing this
12348      *  x.t:(test,tesT) 
12349      * 
12350      */
12351     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12352     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12353     
12354     iterChild : function (node, method) {
12355         
12356         var oldPre = this.inPre;
12357         if (node.tagName == 'PRE') {
12358             this.inPre = true;
12359         }
12360         for( var i = 0; i < node.childNodes.length; i++) {
12361             method.call(this, node.childNodes[i]);
12362         }
12363         this.inPre = oldPre;
12364     },
12365     
12366     
12367     
12368     /**
12369      * compile the template
12370      *
12371      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12372      *
12373      */
12374     compile: function()
12375     {
12376         var s = this.html;
12377         
12378         // covert the html into DOM...
12379         var doc = false;
12380         var div =false;
12381         try {
12382             doc = document.implementation.createHTMLDocument("");
12383             doc.documentElement.innerHTML =   this.html  ;
12384             div = doc.documentElement;
12385         } catch (e) {
12386             // old IE... - nasty -- it causes all sorts of issues.. with
12387             // images getting pulled from server..
12388             div = document.createElement('div');
12389             div.innerHTML = this.html;
12390         }
12391         //doc.documentElement.innerHTML = htmlBody
12392          
12393         
12394         
12395         this.tpls = [];
12396         var _t = this;
12397         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12398         
12399         var tpls = this.tpls;
12400         
12401         // create a top level template from the snippet..
12402         
12403         //Roo.log(div.innerHTML);
12404         
12405         var tpl = {
12406             uid : 'master',
12407             id : this.id++,
12408             attr : false,
12409             value : false,
12410             body : div.innerHTML,
12411             
12412             forCall : false,
12413             execCall : false,
12414             dom : div,
12415             isTop : true
12416             
12417         };
12418         tpls.unshift(tpl);
12419         
12420         
12421         // compile them...
12422         this.tpls = [];
12423         Roo.each(tpls, function(tp){
12424             this.compileTpl(tp);
12425             this.tpls[tp.id] = tp;
12426         }, this);
12427         
12428         this.master = tpls[0];
12429         return this;
12430         
12431         
12432     },
12433     
12434     compileNode : function(node, istop) {
12435         // test for
12436         //Roo.log(node);
12437         
12438         
12439         // skip anything not a tag..
12440         if (node.nodeType != 1) {
12441             if (node.nodeType == 3 && !this.inPre) {
12442                 // reduce white space..
12443                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12444                 
12445             }
12446             return;
12447         }
12448         
12449         var tpl = {
12450             uid : false,
12451             id : false,
12452             attr : false,
12453             value : false,
12454             body : '',
12455             
12456             forCall : false,
12457             execCall : false,
12458             dom : false,
12459             isTop : istop
12460             
12461             
12462         };
12463         
12464         
12465         switch(true) {
12466             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12467             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12468             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12469             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12470             // no default..
12471         }
12472         
12473         
12474         if (!tpl.attr) {
12475             // just itterate children..
12476             this.iterChild(node,this.compileNode);
12477             return;
12478         }
12479         tpl.uid = this.id++;
12480         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12481         node.removeAttribute('roo-'+ tpl.attr);
12482         if (tpl.attr != 'name') {
12483             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12484             node.parentNode.replaceChild(placeholder,  node);
12485         } else {
12486             
12487             var placeholder =  document.createElement('span');
12488             placeholder.className = 'roo-tpl-' + tpl.value;
12489             node.parentNode.replaceChild(placeholder,  node);
12490         }
12491         
12492         // parent now sees '{domtplXXXX}
12493         this.iterChild(node,this.compileNode);
12494         
12495         // we should now have node body...
12496         var div = document.createElement('div');
12497         div.appendChild(node);
12498         tpl.dom = node;
12499         // this has the unfortunate side effect of converting tagged attributes
12500         // eg. href="{...}" into %7C...%7D
12501         // this has been fixed by searching for those combo's although it's a bit hacky..
12502         
12503         
12504         tpl.body = div.innerHTML;
12505         
12506         
12507          
12508         tpl.id = tpl.uid;
12509         switch(tpl.attr) {
12510             case 'for' :
12511                 switch (tpl.value) {
12512                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12513                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12514                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12515                 }
12516                 break;
12517             
12518             case 'exec':
12519                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12520                 break;
12521             
12522             case 'if':     
12523                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12524                 break;
12525             
12526             case 'name':
12527                 tpl.id  = tpl.value; // replace non characters???
12528                 break;
12529             
12530         }
12531         
12532         
12533         this.tpls.push(tpl);
12534         
12535         
12536         
12537     },
12538     
12539     
12540     
12541     
12542     /**
12543      * Compile a segment of the template into a 'sub-template'
12544      *
12545      * 
12546      * 
12547      *
12548      */
12549     compileTpl : function(tpl)
12550     {
12551         var fm = Roo.util.Format;
12552         var useF = this.disableFormats !== true;
12553         
12554         var sep = Roo.isGecko ? "+\n" : ",\n";
12555         
12556         var undef = function(str) {
12557             Roo.debug && Roo.log("Property not found :"  + str);
12558             return '';
12559         };
12560           
12561         //Roo.log(tpl.body);
12562         
12563         
12564         
12565         var fn = function(m, lbrace, name, format, args)
12566         {
12567             //Roo.log("ARGS");
12568             //Roo.log(arguments);
12569             args = args ? args.replace(/\\'/g,"'") : args;
12570             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12571             if (typeof(format) == 'undefined') {
12572                 format =  'htmlEncode'; 
12573             }
12574             if (format == 'raw' ) {
12575                 format = false;
12576             }
12577             
12578             if(name.substr(0, 6) == 'domtpl'){
12579                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12580             }
12581             
12582             // build an array of options to determine if value is undefined..
12583             
12584             // basically get 'xxxx.yyyy' then do
12585             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12586             //    (function () { Roo.log("Property not found"); return ''; })() :
12587             //    ......
12588             
12589             var udef_ar = [];
12590             var lookfor = '';
12591             Roo.each(name.split('.'), function(st) {
12592                 lookfor += (lookfor.length ? '.': '') + st;
12593                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12594             });
12595             
12596             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12597             
12598             
12599             if(format && useF){
12600                 
12601                 args = args ? ',' + args : "";
12602                  
12603                 if(format.substr(0, 5) != "this."){
12604                     format = "fm." + format + '(';
12605                 }else{
12606                     format = 'this.call("'+ format.substr(5) + '", ';
12607                     args = ", values";
12608                 }
12609                 
12610                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12611             }
12612              
12613             if (args && args.length) {
12614                 // called with xxyx.yuu:(test,test)
12615                 // change to ()
12616                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12617             }
12618             // raw.. - :raw modifier..
12619             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12620             
12621         };
12622         var body;
12623         // branched to use + in gecko and [].join() in others
12624         if(Roo.isGecko){
12625             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12626                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12627                     "';};};";
12628         }else{
12629             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12630             body.push(tpl.body.replace(/(\r\n|\n)/g,
12631                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12632             body.push("'].join('');};};");
12633             body = body.join('');
12634         }
12635         
12636         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12637        
12638         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12639         eval(body);
12640         
12641         return this;
12642     },
12643      
12644     /**
12645      * same as applyTemplate, except it's done to one of the subTemplates
12646      * when using named templates, you can do:
12647      *
12648      * var str = pl.applySubTemplate('your-name', values);
12649      *
12650      * 
12651      * @param {Number} id of the template
12652      * @param {Object} values to apply to template
12653      * @param {Object} parent (normaly the instance of this object)
12654      */
12655     applySubTemplate : function(id, values, parent)
12656     {
12657         
12658         
12659         var t = this.tpls[id];
12660         
12661         
12662         try { 
12663             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12664                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12665                 return '';
12666             }
12667         } catch(e) {
12668             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12669             Roo.log(values);
12670           
12671             return '';
12672         }
12673         try { 
12674             
12675             if(t.execCall && t.execCall.call(this, values, parent)){
12676                 return '';
12677             }
12678         } catch(e) {
12679             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12680             Roo.log(values);
12681             return '';
12682         }
12683         
12684         try {
12685             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12686             parent = t.target ? values : parent;
12687             if(t.forCall && vs instanceof Array){
12688                 var buf = [];
12689                 for(var i = 0, len = vs.length; i < len; i++){
12690                     try {
12691                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12692                     } catch (e) {
12693                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12694                         Roo.log(e.body);
12695                         //Roo.log(t.compiled);
12696                         Roo.log(vs[i]);
12697                     }   
12698                 }
12699                 return buf.join('');
12700             }
12701         } catch (e) {
12702             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12703             Roo.log(values);
12704             return '';
12705         }
12706         try {
12707             return t.compiled.call(this, vs, parent);
12708         } catch (e) {
12709             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12710             Roo.log(e.body);
12711             //Roo.log(t.compiled);
12712             Roo.log(values);
12713             return '';
12714         }
12715     },
12716
12717    
12718
12719     applyTemplate : function(values){
12720         return this.master.compiled.call(this, values, {});
12721         //var s = this.subs;
12722     },
12723
12724     apply : function(){
12725         return this.applyTemplate.apply(this, arguments);
12726     }
12727
12728  });
12729
12730 Roo.DomTemplate.from = function(el){
12731     el = Roo.getDom(el);
12732     return new Roo.Domtemplate(el.value || el.innerHTML);
12733 };/*
12734  * Based on:
12735  * Ext JS Library 1.1.1
12736  * Copyright(c) 2006-2007, Ext JS, LLC.
12737  *
12738  * Originally Released Under LGPL - original licence link has changed is not relivant.
12739  *
12740  * Fork - LGPL
12741  * <script type="text/javascript">
12742  */
12743
12744 /**
12745  * @class Roo.util.DelayedTask
12746  * Provides a convenient method of performing setTimeout where a new
12747  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12748  * You can use this class to buffer
12749  * the keypress events for a certain number of milliseconds, and perform only if they stop
12750  * for that amount of time.
12751  * @constructor The parameters to this constructor serve as defaults and are not required.
12752  * @param {Function} fn (optional) The default function to timeout
12753  * @param {Object} scope (optional) The default scope of that timeout
12754  * @param {Array} args (optional) The default Array of arguments
12755  */
12756 Roo.util.DelayedTask = function(fn, scope, args){
12757     var id = null, d, t;
12758
12759     var call = function(){
12760         var now = new Date().getTime();
12761         if(now - t >= d){
12762             clearInterval(id);
12763             id = null;
12764             fn.apply(scope, args || []);
12765         }
12766     };
12767     /**
12768      * Cancels any pending timeout and queues a new one
12769      * @param {Number} delay The milliseconds to delay
12770      * @param {Function} newFn (optional) Overrides function passed to constructor
12771      * @param {Object} newScope (optional) Overrides scope passed to constructor
12772      * @param {Array} newArgs (optional) Overrides args passed to constructor
12773      */
12774     this.delay = function(delay, newFn, newScope, newArgs){
12775         if(id && delay != d){
12776             this.cancel();
12777         }
12778         d = delay;
12779         t = new Date().getTime();
12780         fn = newFn || fn;
12781         scope = newScope || scope;
12782         args = newArgs || args;
12783         if(!id){
12784             id = setInterval(call, d);
12785         }
12786     };
12787
12788     /**
12789      * Cancel the last queued timeout
12790      */
12791     this.cancel = function(){
12792         if(id){
12793             clearInterval(id);
12794             id = null;
12795         }
12796     };
12797 };/*
12798  * Based on:
12799  * Ext JS Library 1.1.1
12800  * Copyright(c) 2006-2007, Ext JS, LLC.
12801  *
12802  * Originally Released Under LGPL - original licence link has changed is not relivant.
12803  *
12804  * Fork - LGPL
12805  * <script type="text/javascript">
12806  */
12807  
12808  
12809 Roo.util.TaskRunner = function(interval){
12810     interval = interval || 10;
12811     var tasks = [], removeQueue = [];
12812     var id = 0;
12813     var running = false;
12814
12815     var stopThread = function(){
12816         running = false;
12817         clearInterval(id);
12818         id = 0;
12819     };
12820
12821     var startThread = function(){
12822         if(!running){
12823             running = true;
12824             id = setInterval(runTasks, interval);
12825         }
12826     };
12827
12828     var removeTask = function(task){
12829         removeQueue.push(task);
12830         if(task.onStop){
12831             task.onStop();
12832         }
12833     };
12834
12835     var runTasks = function(){
12836         if(removeQueue.length > 0){
12837             for(var i = 0, len = removeQueue.length; i < len; i++){
12838                 tasks.remove(removeQueue[i]);
12839             }
12840             removeQueue = [];
12841             if(tasks.length < 1){
12842                 stopThread();
12843                 return;
12844             }
12845         }
12846         var now = new Date().getTime();
12847         for(var i = 0, len = tasks.length; i < len; ++i){
12848             var t = tasks[i];
12849             var itime = now - t.taskRunTime;
12850             if(t.interval <= itime){
12851                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12852                 t.taskRunTime = now;
12853                 if(rt === false || t.taskRunCount === t.repeat){
12854                     removeTask(t);
12855                     return;
12856                 }
12857             }
12858             if(t.duration && t.duration <= (now - t.taskStartTime)){
12859                 removeTask(t);
12860             }
12861         }
12862     };
12863
12864     /**
12865      * Queues a new task.
12866      * @param {Object} task
12867      */
12868     this.start = function(task){
12869         tasks.push(task);
12870         task.taskStartTime = new Date().getTime();
12871         task.taskRunTime = 0;
12872         task.taskRunCount = 0;
12873         startThread();
12874         return task;
12875     };
12876
12877     this.stop = function(task){
12878         removeTask(task);
12879         return task;
12880     };
12881
12882     this.stopAll = function(){
12883         stopThread();
12884         for(var i = 0, len = tasks.length; i < len; i++){
12885             if(tasks[i].onStop){
12886                 tasks[i].onStop();
12887             }
12888         }
12889         tasks = [];
12890         removeQueue = [];
12891     };
12892 };
12893
12894 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12895  * Based on:
12896  * Ext JS Library 1.1.1
12897  * Copyright(c) 2006-2007, Ext JS, LLC.
12898  *
12899  * Originally Released Under LGPL - original licence link has changed is not relivant.
12900  *
12901  * Fork - LGPL
12902  * <script type="text/javascript">
12903  */
12904
12905  
12906 /**
12907  * @class Roo.util.MixedCollection
12908  * @extends Roo.util.Observable
12909  * A Collection class that maintains both numeric indexes and keys and exposes events.
12910  * @constructor
12911  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12912  * collection (defaults to false)
12913  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12914  * and return the key value for that item.  This is used when available to look up the key on items that
12915  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12916  * equivalent to providing an implementation for the {@link #getKey} method.
12917  */
12918 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12919     this.items = [];
12920     this.map = {};
12921     this.keys = [];
12922     this.length = 0;
12923     this.addEvents({
12924         /**
12925          * @event clear
12926          * Fires when the collection is cleared.
12927          */
12928         "clear" : true,
12929         /**
12930          * @event add
12931          * Fires when an item is added to the collection.
12932          * @param {Number} index The index at which the item was added.
12933          * @param {Object} o The item added.
12934          * @param {String} key The key associated with the added item.
12935          */
12936         "add" : true,
12937         /**
12938          * @event replace
12939          * Fires when an item is replaced in the collection.
12940          * @param {String} key he key associated with the new added.
12941          * @param {Object} old The item being replaced.
12942          * @param {Object} new The new item.
12943          */
12944         "replace" : true,
12945         /**
12946          * @event remove
12947          * Fires when an item is removed from the collection.
12948          * @param {Object} o The item being removed.
12949          * @param {String} key (optional) The key associated with the removed item.
12950          */
12951         "remove" : true,
12952         "sort" : true
12953     });
12954     this.allowFunctions = allowFunctions === true;
12955     if(keyFn){
12956         this.getKey = keyFn;
12957     }
12958     Roo.util.MixedCollection.superclass.constructor.call(this);
12959 };
12960
12961 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12962     allowFunctions : false,
12963     
12964 /**
12965  * Adds an item to the collection.
12966  * @param {String} key The key to associate with the item
12967  * @param {Object} o The item to add.
12968  * @return {Object} The item added.
12969  */
12970     add : function(key, o){
12971         if(arguments.length == 1){
12972             o = arguments[0];
12973             key = this.getKey(o);
12974         }
12975         if(typeof key == "undefined" || key === null){
12976             this.length++;
12977             this.items.push(o);
12978             this.keys.push(null);
12979         }else{
12980             var old = this.map[key];
12981             if(old){
12982                 return this.replace(key, o);
12983             }
12984             this.length++;
12985             this.items.push(o);
12986             this.map[key] = o;
12987             this.keys.push(key);
12988         }
12989         this.fireEvent("add", this.length-1, o, key);
12990         return o;
12991     },
12992        
12993 /**
12994   * MixedCollection has a generic way to fetch keys if you implement getKey.
12995 <pre><code>
12996 // normal way
12997 var mc = new Roo.util.MixedCollection();
12998 mc.add(someEl.dom.id, someEl);
12999 mc.add(otherEl.dom.id, otherEl);
13000 //and so on
13001
13002 // using getKey
13003 var mc = new Roo.util.MixedCollection();
13004 mc.getKey = function(el){
13005    return el.dom.id;
13006 };
13007 mc.add(someEl);
13008 mc.add(otherEl);
13009
13010 // or via the constructor
13011 var mc = new Roo.util.MixedCollection(false, function(el){
13012    return el.dom.id;
13013 });
13014 mc.add(someEl);
13015 mc.add(otherEl);
13016 </code></pre>
13017  * @param o {Object} The item for which to find the key.
13018  * @return {Object} The key for the passed item.
13019  */
13020     getKey : function(o){
13021          return o.id; 
13022     },
13023    
13024 /**
13025  * Replaces an item in the collection.
13026  * @param {String} key The key associated with the item to replace, or the item to replace.
13027  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13028  * @return {Object}  The new item.
13029  */
13030     replace : function(key, o){
13031         if(arguments.length == 1){
13032             o = arguments[0];
13033             key = this.getKey(o);
13034         }
13035         var old = this.item(key);
13036         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13037              return this.add(key, o);
13038         }
13039         var index = this.indexOfKey(key);
13040         this.items[index] = o;
13041         this.map[key] = o;
13042         this.fireEvent("replace", key, old, o);
13043         return o;
13044     },
13045    
13046 /**
13047  * Adds all elements of an Array or an Object to the collection.
13048  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13049  * an Array of values, each of which are added to the collection.
13050  */
13051     addAll : function(objs){
13052         if(arguments.length > 1 || objs instanceof Array){
13053             var args = arguments.length > 1 ? arguments : objs;
13054             for(var i = 0, len = args.length; i < len; i++){
13055                 this.add(args[i]);
13056             }
13057         }else{
13058             for(var key in objs){
13059                 if(this.allowFunctions || typeof objs[key] != "function"){
13060                     this.add(key, objs[key]);
13061                 }
13062             }
13063         }
13064     },
13065    
13066 /**
13067  * Executes the specified function once for every item in the collection, passing each
13068  * item as the first and only parameter. returning false from the function will stop the iteration.
13069  * @param {Function} fn The function to execute for each item.
13070  * @param {Object} scope (optional) The scope in which to execute the function.
13071  */
13072     each : function(fn, scope){
13073         var items = [].concat(this.items); // each safe for removal
13074         for(var i = 0, len = items.length; i < len; i++){
13075             if(fn.call(scope || items[i], items[i], i, len) === false){
13076                 break;
13077             }
13078         }
13079     },
13080    
13081 /**
13082  * Executes the specified function once for every key in the collection, passing each
13083  * key, and its associated item as the first two parameters.
13084  * @param {Function} fn The function to execute for each item.
13085  * @param {Object} scope (optional) The scope in which to execute the function.
13086  */
13087     eachKey : function(fn, scope){
13088         for(var i = 0, len = this.keys.length; i < len; i++){
13089             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13090         }
13091     },
13092    
13093 /**
13094  * Returns the first item in the collection which elicits a true return value from the
13095  * passed selection function.
13096  * @param {Function} fn The selection function to execute for each item.
13097  * @param {Object} scope (optional) The scope in which to execute the function.
13098  * @return {Object} The first item in the collection which returned true from the selection function.
13099  */
13100     find : function(fn, scope){
13101         for(var i = 0, len = this.items.length; i < len; i++){
13102             if(fn.call(scope || window, this.items[i], this.keys[i])){
13103                 return this.items[i];
13104             }
13105         }
13106         return null;
13107     },
13108    
13109 /**
13110  * Inserts an item at the specified index in the collection.
13111  * @param {Number} index The index to insert the item at.
13112  * @param {String} key The key to associate with the new item, or the item itself.
13113  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13114  * @return {Object} The item inserted.
13115  */
13116     insert : function(index, key, o){
13117         if(arguments.length == 2){
13118             o = arguments[1];
13119             key = this.getKey(o);
13120         }
13121         if(index >= this.length){
13122             return this.add(key, o);
13123         }
13124         this.length++;
13125         this.items.splice(index, 0, o);
13126         if(typeof key != "undefined" && key != null){
13127             this.map[key] = o;
13128         }
13129         this.keys.splice(index, 0, key);
13130         this.fireEvent("add", index, o, key);
13131         return o;
13132     },
13133    
13134 /**
13135  * Removed an item from the collection.
13136  * @param {Object} o The item to remove.
13137  * @return {Object} The item removed.
13138  */
13139     remove : function(o){
13140         return this.removeAt(this.indexOf(o));
13141     },
13142    
13143 /**
13144  * Remove an item from a specified index in the collection.
13145  * @param {Number} index The index within the collection of the item to remove.
13146  */
13147     removeAt : function(index){
13148         if(index < this.length && index >= 0){
13149             this.length--;
13150             var o = this.items[index];
13151             this.items.splice(index, 1);
13152             var key = this.keys[index];
13153             if(typeof key != "undefined"){
13154                 delete this.map[key];
13155             }
13156             this.keys.splice(index, 1);
13157             this.fireEvent("remove", o, key);
13158         }
13159     },
13160    
13161 /**
13162  * Removed an item associated with the passed key fom the collection.
13163  * @param {String} key The key of the item to remove.
13164  */
13165     removeKey : function(key){
13166         return this.removeAt(this.indexOfKey(key));
13167     },
13168    
13169 /**
13170  * Returns the number of items in the collection.
13171  * @return {Number} the number of items in the collection.
13172  */
13173     getCount : function(){
13174         return this.length; 
13175     },
13176    
13177 /**
13178  * Returns index within the collection of the passed Object.
13179  * @param {Object} o The item to find the index of.
13180  * @return {Number} index of the item.
13181  */
13182     indexOf : function(o){
13183         if(!this.items.indexOf){
13184             for(var i = 0, len = this.items.length; i < len; i++){
13185                 if(this.items[i] == o) {
13186                     return i;
13187                 }
13188             }
13189             return -1;
13190         }else{
13191             return this.items.indexOf(o);
13192         }
13193     },
13194    
13195 /**
13196  * Returns index within the collection of the passed key.
13197  * @param {String} key The key to find the index of.
13198  * @return {Number} index of the key.
13199  */
13200     indexOfKey : function(key){
13201         if(!this.keys.indexOf){
13202             for(var i = 0, len = this.keys.length; i < len; i++){
13203                 if(this.keys[i] == key) {
13204                     return i;
13205                 }
13206             }
13207             return -1;
13208         }else{
13209             return this.keys.indexOf(key);
13210         }
13211     },
13212    
13213 /**
13214  * Returns the item associated with the passed key OR index. Key has priority over index.
13215  * @param {String/Number} key The key or index of the item.
13216  * @return {Object} The item associated with the passed key.
13217  */
13218     item : function(key){
13219         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13220         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13221     },
13222     
13223 /**
13224  * Returns the item at the specified index.
13225  * @param {Number} index The index of the item.
13226  * @return {Object}
13227  */
13228     itemAt : function(index){
13229         return this.items[index];
13230     },
13231     
13232 /**
13233  * Returns the item associated with the passed key.
13234  * @param {String/Number} key The key of the item.
13235  * @return {Object} The item associated with the passed key.
13236  */
13237     key : function(key){
13238         return this.map[key];
13239     },
13240    
13241 /**
13242  * Returns true if the collection contains the passed Object as an item.
13243  * @param {Object} o  The Object to look for in the collection.
13244  * @return {Boolean} True if the collection contains the Object as an item.
13245  */
13246     contains : function(o){
13247         return this.indexOf(o) != -1;
13248     },
13249    
13250 /**
13251  * Returns true if the collection contains the passed Object as a key.
13252  * @param {String} key The key to look for in the collection.
13253  * @return {Boolean} True if the collection contains the Object as a key.
13254  */
13255     containsKey : function(key){
13256         return typeof this.map[key] != "undefined";
13257     },
13258    
13259 /**
13260  * Removes all items from the collection.
13261  */
13262     clear : function(){
13263         this.length = 0;
13264         this.items = [];
13265         this.keys = [];
13266         this.map = {};
13267         this.fireEvent("clear");
13268     },
13269    
13270 /**
13271  * Returns the first item in the collection.
13272  * @return {Object} the first item in the collection..
13273  */
13274     first : function(){
13275         return this.items[0]; 
13276     },
13277    
13278 /**
13279  * Returns the last item in the collection.
13280  * @return {Object} the last item in the collection..
13281  */
13282     last : function(){
13283         return this.items[this.length-1];   
13284     },
13285     
13286     _sort : function(property, dir, fn){
13287         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13288         fn = fn || function(a, b){
13289             return a-b;
13290         };
13291         var c = [], k = this.keys, items = this.items;
13292         for(var i = 0, len = items.length; i < len; i++){
13293             c[c.length] = {key: k[i], value: items[i], index: i};
13294         }
13295         c.sort(function(a, b){
13296             var v = fn(a[property], b[property]) * dsc;
13297             if(v == 0){
13298                 v = (a.index < b.index ? -1 : 1);
13299             }
13300             return v;
13301         });
13302         for(var i = 0, len = c.length; i < len; i++){
13303             items[i] = c[i].value;
13304             k[i] = c[i].key;
13305         }
13306         this.fireEvent("sort", this);
13307     },
13308     
13309     /**
13310      * Sorts this collection with the passed comparison function
13311      * @param {String} direction (optional) "ASC" or "DESC"
13312      * @param {Function} fn (optional) comparison function
13313      */
13314     sort : function(dir, fn){
13315         this._sort("value", dir, fn);
13316     },
13317     
13318     /**
13319      * Sorts this collection by keys
13320      * @param {String} direction (optional) "ASC" or "DESC"
13321      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13322      */
13323     keySort : function(dir, fn){
13324         this._sort("key", dir, fn || function(a, b){
13325             return String(a).toUpperCase()-String(b).toUpperCase();
13326         });
13327     },
13328     
13329     /**
13330      * Returns a range of items in this collection
13331      * @param {Number} startIndex (optional) defaults to 0
13332      * @param {Number} endIndex (optional) default to the last item
13333      * @return {Array} An array of items
13334      */
13335     getRange : function(start, end){
13336         var items = this.items;
13337         if(items.length < 1){
13338             return [];
13339         }
13340         start = start || 0;
13341         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13342         var r = [];
13343         if(start <= end){
13344             for(var i = start; i <= end; i++) {
13345                     r[r.length] = items[i];
13346             }
13347         }else{
13348             for(var i = start; i >= end; i--) {
13349                     r[r.length] = items[i];
13350             }
13351         }
13352         return r;
13353     },
13354         
13355     /**
13356      * Filter the <i>objects</i> in this collection by a specific property. 
13357      * Returns a new collection that has been filtered.
13358      * @param {String} property A property on your objects
13359      * @param {String/RegExp} value Either string that the property values 
13360      * should start with or a RegExp to test against the property
13361      * @return {MixedCollection} The new filtered collection
13362      */
13363     filter : function(property, value){
13364         if(!value.exec){ // not a regex
13365             value = String(value);
13366             if(value.length == 0){
13367                 return this.clone();
13368             }
13369             value = new RegExp("^" + Roo.escapeRe(value), "i");
13370         }
13371         return this.filterBy(function(o){
13372             return o && value.test(o[property]);
13373         });
13374         },
13375     
13376     /**
13377      * Filter by a function. * Returns a new collection that has been filtered.
13378      * The passed function will be called with each 
13379      * object in the collection. If the function returns true, the value is included 
13380      * otherwise it is filtered.
13381      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13382      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13383      * @return {MixedCollection} The new filtered collection
13384      */
13385     filterBy : function(fn, scope){
13386         var r = new Roo.util.MixedCollection();
13387         r.getKey = this.getKey;
13388         var k = this.keys, it = this.items;
13389         for(var i = 0, len = it.length; i < len; i++){
13390             if(fn.call(scope||this, it[i], k[i])){
13391                                 r.add(k[i], it[i]);
13392                         }
13393         }
13394         return r;
13395     },
13396     
13397     /**
13398      * Creates a duplicate of this collection
13399      * @return {MixedCollection}
13400      */
13401     clone : function(){
13402         var r = new Roo.util.MixedCollection();
13403         var k = this.keys, it = this.items;
13404         for(var i = 0, len = it.length; i < len; i++){
13405             r.add(k[i], it[i]);
13406         }
13407         r.getKey = this.getKey;
13408         return r;
13409     }
13410 });
13411 /**
13412  * Returns the item associated with the passed key or index.
13413  * @method
13414  * @param {String/Number} key The key or index of the item.
13415  * @return {Object} The item associated with the passed key.
13416  */
13417 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13418  * Based on:
13419  * Ext JS Library 1.1.1
13420  * Copyright(c) 2006-2007, Ext JS, LLC.
13421  *
13422  * Originally Released Under LGPL - original licence link has changed is not relivant.
13423  *
13424  * Fork - LGPL
13425  * <script type="text/javascript">
13426  */
13427 /**
13428  * @class Roo.util.JSON
13429  * Modified version of Douglas Crockford"s json.js that doesn"t
13430  * mess with the Object prototype 
13431  * http://www.json.org/js.html
13432  * @singleton
13433  */
13434 Roo.util.JSON = new (function(){
13435     var useHasOwn = {}.hasOwnProperty ? true : false;
13436     
13437     // crashes Safari in some instances
13438     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13439     
13440     var pad = function(n) {
13441         return n < 10 ? "0" + n : n;
13442     };
13443     
13444     var m = {
13445         "\b": '\\b',
13446         "\t": '\\t',
13447         "\n": '\\n',
13448         "\f": '\\f',
13449         "\r": '\\r',
13450         '"' : '\\"',
13451         "\\": '\\\\'
13452     };
13453
13454     var encodeString = function(s){
13455         if (/["\\\x00-\x1f]/.test(s)) {
13456             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13457                 var c = m[b];
13458                 if(c){
13459                     return c;
13460                 }
13461                 c = b.charCodeAt();
13462                 return "\\u00" +
13463                     Math.floor(c / 16).toString(16) +
13464                     (c % 16).toString(16);
13465             }) + '"';
13466         }
13467         return '"' + s + '"';
13468     };
13469     
13470     var encodeArray = function(o){
13471         var a = ["["], b, i, l = o.length, v;
13472             for (i = 0; i < l; i += 1) {
13473                 v = o[i];
13474                 switch (typeof v) {
13475                     case "undefined":
13476                     case "function":
13477                     case "unknown":
13478                         break;
13479                     default:
13480                         if (b) {
13481                             a.push(',');
13482                         }
13483                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13484                         b = true;
13485                 }
13486             }
13487             a.push("]");
13488             return a.join("");
13489     };
13490     
13491     var encodeDate = function(o){
13492         return '"' + o.getFullYear() + "-" +
13493                 pad(o.getMonth() + 1) + "-" +
13494                 pad(o.getDate()) + "T" +
13495                 pad(o.getHours()) + ":" +
13496                 pad(o.getMinutes()) + ":" +
13497                 pad(o.getSeconds()) + '"';
13498     };
13499     
13500     /**
13501      * Encodes an Object, Array or other value
13502      * @param {Mixed} o The variable to encode
13503      * @return {String} The JSON string
13504      */
13505     this.encode = function(o)
13506     {
13507         // should this be extended to fully wrap stringify..
13508         
13509         if(typeof o == "undefined" || o === null){
13510             return "null";
13511         }else if(o instanceof Array){
13512             return encodeArray(o);
13513         }else if(o instanceof Date){
13514             return encodeDate(o);
13515         }else if(typeof o == "string"){
13516             return encodeString(o);
13517         }else if(typeof o == "number"){
13518             return isFinite(o) ? String(o) : "null";
13519         }else if(typeof o == "boolean"){
13520             return String(o);
13521         }else {
13522             var a = ["{"], b, i, v;
13523             for (i in o) {
13524                 if(!useHasOwn || o.hasOwnProperty(i)) {
13525                     v = o[i];
13526                     switch (typeof v) {
13527                     case "undefined":
13528                     case "function":
13529                     case "unknown":
13530                         break;
13531                     default:
13532                         if(b){
13533                             a.push(',');
13534                         }
13535                         a.push(this.encode(i), ":",
13536                                 v === null ? "null" : this.encode(v));
13537                         b = true;
13538                     }
13539                 }
13540             }
13541             a.push("}");
13542             return a.join("");
13543         }
13544     };
13545     
13546     /**
13547      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13548      * @param {String} json The JSON string
13549      * @return {Object} The resulting object
13550      */
13551     this.decode = function(json){
13552         
13553         return  /** eval:var:json */ eval("(" + json + ')');
13554     };
13555 })();
13556 /** 
13557  * Shorthand for {@link Roo.util.JSON#encode}
13558  * @member Roo encode 
13559  * @method */
13560 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13561 /** 
13562  * Shorthand for {@link Roo.util.JSON#decode}
13563  * @member Roo decode 
13564  * @method */
13565 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13566 /*
13567  * Based on:
13568  * Ext JS Library 1.1.1
13569  * Copyright(c) 2006-2007, Ext JS, LLC.
13570  *
13571  * Originally Released Under LGPL - original licence link has changed is not relivant.
13572  *
13573  * Fork - LGPL
13574  * <script type="text/javascript">
13575  */
13576  
13577 /**
13578  * @class Roo.util.Format
13579  * Reusable data formatting functions
13580  * @singleton
13581  */
13582 Roo.util.Format = function(){
13583     var trimRe = /^\s+|\s+$/g;
13584     return {
13585         /**
13586          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13587          * @param {String} value The string to truncate
13588          * @param {Number} length The maximum length to allow before truncating
13589          * @return {String} The converted text
13590          */
13591         ellipsis : function(value, len){
13592             if(value && value.length > len){
13593                 return value.substr(0, len-3)+"...";
13594             }
13595             return value;
13596         },
13597
13598         /**
13599          * Checks a reference and converts it to empty string if it is undefined
13600          * @param {Mixed} value Reference to check
13601          * @return {Mixed} Empty string if converted, otherwise the original value
13602          */
13603         undef : function(value){
13604             return typeof value != "undefined" ? value : "";
13605         },
13606
13607         /**
13608          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13609          * @param {String} value The string to encode
13610          * @return {String} The encoded text
13611          */
13612         htmlEncode : function(value){
13613             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13614         },
13615
13616         /**
13617          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13618          * @param {String} value The string to decode
13619          * @return {String} The decoded text
13620          */
13621         htmlDecode : function(value){
13622             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13623         },
13624
13625         /**
13626          * Trims any whitespace from either side of a string
13627          * @param {String} value The text to trim
13628          * @return {String} The trimmed text
13629          */
13630         trim : function(value){
13631             return String(value).replace(trimRe, "");
13632         },
13633
13634         /**
13635          * Returns a substring from within an original string
13636          * @param {String} value The original text
13637          * @param {Number} start The start index of the substring
13638          * @param {Number} length The length of the substring
13639          * @return {String} The substring
13640          */
13641         substr : function(value, start, length){
13642             return String(value).substr(start, length);
13643         },
13644
13645         /**
13646          * Converts a string to all lower case letters
13647          * @param {String} value The text to convert
13648          * @return {String} The converted text
13649          */
13650         lowercase : function(value){
13651             return String(value).toLowerCase();
13652         },
13653
13654         /**
13655          * Converts a string to all upper case letters
13656          * @param {String} value The text to convert
13657          * @return {String} The converted text
13658          */
13659         uppercase : function(value){
13660             return String(value).toUpperCase();
13661         },
13662
13663         /**
13664          * Converts the first character only of a string to upper case
13665          * @param {String} value The text to convert
13666          * @return {String} The converted text
13667          */
13668         capitalize : function(value){
13669             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13670         },
13671
13672         // private
13673         call : function(value, fn){
13674             if(arguments.length > 2){
13675                 var args = Array.prototype.slice.call(arguments, 2);
13676                 args.unshift(value);
13677                  
13678                 return /** eval:var:value */  eval(fn).apply(window, args);
13679             }else{
13680                 /** eval:var:value */
13681                 return /** eval:var:value */ eval(fn).call(window, value);
13682             }
13683         },
13684
13685        
13686         /**
13687          * safer version of Math.toFixed..??/
13688          * @param {Number/String} value The numeric value to format
13689          * @param {Number/String} value Decimal places 
13690          * @return {String} The formatted currency string
13691          */
13692         toFixed : function(v, n)
13693         {
13694             // why not use to fixed - precision is buggered???
13695             if (!n) {
13696                 return Math.round(v-0);
13697             }
13698             var fact = Math.pow(10,n+1);
13699             v = (Math.round((v-0)*fact))/fact;
13700             var z = (''+fact).substring(2);
13701             if (v == Math.floor(v)) {
13702                 return Math.floor(v) + '.' + z;
13703             }
13704             
13705             // now just padd decimals..
13706             var ps = String(v).split('.');
13707             var fd = (ps[1] + z);
13708             var r = fd.substring(0,n); 
13709             var rm = fd.substring(n); 
13710             if (rm < 5) {
13711                 return ps[0] + '.' + r;
13712             }
13713             r*=1; // turn it into a number;
13714             r++;
13715             if (String(r).length != n) {
13716                 ps[0]*=1;
13717                 ps[0]++;
13718                 r = String(r).substring(1); // chop the end off.
13719             }
13720             
13721             return ps[0] + '.' + r;
13722              
13723         },
13724         
13725         /**
13726          * Format a number as US currency
13727          * @param {Number/String} value The numeric value to format
13728          * @return {String} The formatted currency string
13729          */
13730         usMoney : function(v){
13731             return '$' + Roo.util.Format.number(v);
13732         },
13733         
13734         /**
13735          * Format a number
13736          * eventually this should probably emulate php's number_format
13737          * @param {Number/String} value The numeric value to format
13738          * @param {Number} decimals number of decimal places
13739          * @return {String} The formatted currency string
13740          */
13741         number : function(v,decimals)
13742         {
13743             // multiply and round.
13744             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13745             var mul = Math.pow(10, decimals);
13746             var zero = String(mul).substring(1);
13747             v = (Math.round((v-0)*mul))/mul;
13748             
13749             // if it's '0' number.. then
13750             
13751             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13752             v = String(v);
13753             var ps = v.split('.');
13754             var whole = ps[0];
13755             
13756             
13757             var r = /(\d+)(\d{3})/;
13758             // add comma's
13759             while (r.test(whole)) {
13760                 whole = whole.replace(r, '$1' + ',' + '$2');
13761             }
13762             
13763             
13764             var sub = ps[1] ?
13765                     // has decimals..
13766                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13767                     // does not have decimals
13768                     (decimals ? ('.' + zero) : '');
13769             
13770             
13771             return whole + sub ;
13772         },
13773         
13774         /**
13775          * Parse a value into a formatted date using the specified format pattern.
13776          * @param {Mixed} value The value to format
13777          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13778          * @return {String} The formatted date string
13779          */
13780         date : function(v, format){
13781             if(!v){
13782                 return "";
13783             }
13784             if(!(v instanceof Date)){
13785                 v = new Date(Date.parse(v));
13786             }
13787             return v.dateFormat(format || Roo.util.Format.defaults.date);
13788         },
13789
13790         /**
13791          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13792          * @param {String} format Any valid date format string
13793          * @return {Function} The date formatting function
13794          */
13795         dateRenderer : function(format){
13796             return function(v){
13797                 return Roo.util.Format.date(v, format);  
13798             };
13799         },
13800
13801         // private
13802         stripTagsRE : /<\/?[^>]+>/gi,
13803         
13804         /**
13805          * Strips all HTML tags
13806          * @param {Mixed} value The text from which to strip tags
13807          * @return {String} The stripped text
13808          */
13809         stripTags : function(v){
13810             return !v ? v : String(v).replace(this.stripTagsRE, "");
13811         }
13812     };
13813 }();
13814 Roo.util.Format.defaults = {
13815     date : 'd/M/Y'
13816 };/*
13817  * Based on:
13818  * Ext JS Library 1.1.1
13819  * Copyright(c) 2006-2007, Ext JS, LLC.
13820  *
13821  * Originally Released Under LGPL - original licence link has changed is not relivant.
13822  *
13823  * Fork - LGPL
13824  * <script type="text/javascript">
13825  */
13826
13827
13828  
13829
13830 /**
13831  * @class Roo.MasterTemplate
13832  * @extends Roo.Template
13833  * Provides a template that can have child templates. The syntax is:
13834 <pre><code>
13835 var t = new Roo.MasterTemplate(
13836         '&lt;select name="{name}"&gt;',
13837                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13838         '&lt;/select&gt;'
13839 );
13840 t.add('options', {value: 'foo', text: 'bar'});
13841 // or you can add multiple child elements in one shot
13842 t.addAll('options', [
13843     {value: 'foo', text: 'bar'},
13844     {value: 'foo2', text: 'bar2'},
13845     {value: 'foo3', text: 'bar3'}
13846 ]);
13847 // then append, applying the master template values
13848 t.append('my-form', {name: 'my-select'});
13849 </code></pre>
13850 * A name attribute for the child template is not required if you have only one child
13851 * template or you want to refer to them by index.
13852  */
13853 Roo.MasterTemplate = function(){
13854     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13855     this.originalHtml = this.html;
13856     var st = {};
13857     var m, re = this.subTemplateRe;
13858     re.lastIndex = 0;
13859     var subIndex = 0;
13860     while(m = re.exec(this.html)){
13861         var name = m[1], content = m[2];
13862         st[subIndex] = {
13863             name: name,
13864             index: subIndex,
13865             buffer: [],
13866             tpl : new Roo.Template(content)
13867         };
13868         if(name){
13869             st[name] = st[subIndex];
13870         }
13871         st[subIndex].tpl.compile();
13872         st[subIndex].tpl.call = this.call.createDelegate(this);
13873         subIndex++;
13874     }
13875     this.subCount = subIndex;
13876     this.subs = st;
13877 };
13878 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13879     /**
13880     * The regular expression used to match sub templates
13881     * @type RegExp
13882     * @property
13883     */
13884     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13885
13886     /**
13887      * Applies the passed values to a child template.
13888      * @param {String/Number} name (optional) The name or index of the child template
13889      * @param {Array/Object} values The values to be applied to the template
13890      * @return {MasterTemplate} this
13891      */
13892      add : function(name, values){
13893         if(arguments.length == 1){
13894             values = arguments[0];
13895             name = 0;
13896         }
13897         var s = this.subs[name];
13898         s.buffer[s.buffer.length] = s.tpl.apply(values);
13899         return this;
13900     },
13901
13902     /**
13903      * Applies all the passed values to a child template.
13904      * @param {String/Number} name (optional) The name or index of the child template
13905      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13906      * @param {Boolean} reset (optional) True to reset the template first
13907      * @return {MasterTemplate} this
13908      */
13909     fill : function(name, values, reset){
13910         var a = arguments;
13911         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13912             values = a[0];
13913             name = 0;
13914             reset = a[1];
13915         }
13916         if(reset){
13917             this.reset();
13918         }
13919         for(var i = 0, len = values.length; i < len; i++){
13920             this.add(name, values[i]);
13921         }
13922         return this;
13923     },
13924
13925     /**
13926      * Resets the template for reuse
13927      * @return {MasterTemplate} this
13928      */
13929      reset : function(){
13930         var s = this.subs;
13931         for(var i = 0; i < this.subCount; i++){
13932             s[i].buffer = [];
13933         }
13934         return this;
13935     },
13936
13937     applyTemplate : function(values){
13938         var s = this.subs;
13939         var replaceIndex = -1;
13940         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13941             return s[++replaceIndex].buffer.join("");
13942         });
13943         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13944     },
13945
13946     apply : function(){
13947         return this.applyTemplate.apply(this, arguments);
13948     },
13949
13950     compile : function(){return this;}
13951 });
13952
13953 /**
13954  * Alias for fill().
13955  * @method
13956  */
13957 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13958  /**
13959  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13960  * var tpl = Roo.MasterTemplate.from('element-id');
13961  * @param {String/HTMLElement} el
13962  * @param {Object} config
13963  * @static
13964  */
13965 Roo.MasterTemplate.from = function(el, config){
13966     el = Roo.getDom(el);
13967     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13968 };/*
13969  * Based on:
13970  * Ext JS Library 1.1.1
13971  * Copyright(c) 2006-2007, Ext JS, LLC.
13972  *
13973  * Originally Released Under LGPL - original licence link has changed is not relivant.
13974  *
13975  * Fork - LGPL
13976  * <script type="text/javascript">
13977  */
13978
13979  
13980 /**
13981  * @class Roo.util.CSS
13982  * Utility class for manipulating CSS rules
13983  * @singleton
13984  */
13985 Roo.util.CSS = function(){
13986         var rules = null;
13987         var doc = document;
13988
13989     var camelRe = /(-[a-z])/gi;
13990     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13991
13992    return {
13993    /**
13994     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13995     * tag and appended to the HEAD of the document.
13996     * @param {String|Object} cssText The text containing the css rules
13997     * @param {String} id An id to add to the stylesheet for later removal
13998     * @return {StyleSheet}
13999     */
14000     createStyleSheet : function(cssText, id){
14001         var ss;
14002         var head = doc.getElementsByTagName("head")[0];
14003         var nrules = doc.createElement("style");
14004         nrules.setAttribute("type", "text/css");
14005         if(id){
14006             nrules.setAttribute("id", id);
14007         }
14008         if (typeof(cssText) != 'string') {
14009             // support object maps..
14010             // not sure if this a good idea.. 
14011             // perhaps it should be merged with the general css handling
14012             // and handle js style props.
14013             var cssTextNew = [];
14014             for(var n in cssText) {
14015                 var citems = [];
14016                 for(var k in cssText[n]) {
14017                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14018                 }
14019                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14020                 
14021             }
14022             cssText = cssTextNew.join("\n");
14023             
14024         }
14025        
14026        
14027        if(Roo.isIE){
14028            head.appendChild(nrules);
14029            ss = nrules.styleSheet;
14030            ss.cssText = cssText;
14031        }else{
14032            try{
14033                 nrules.appendChild(doc.createTextNode(cssText));
14034            }catch(e){
14035                nrules.cssText = cssText; 
14036            }
14037            head.appendChild(nrules);
14038            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14039        }
14040        this.cacheStyleSheet(ss);
14041        return ss;
14042    },
14043
14044    /**
14045     * Removes a style or link tag by id
14046     * @param {String} id The id of the tag
14047     */
14048    removeStyleSheet : function(id){
14049        var existing = doc.getElementById(id);
14050        if(existing){
14051            existing.parentNode.removeChild(existing);
14052        }
14053    },
14054
14055    /**
14056     * Dynamically swaps an existing stylesheet reference for a new one
14057     * @param {String} id The id of an existing link tag to remove
14058     * @param {String} url The href of the new stylesheet to include
14059     */
14060    swapStyleSheet : function(id, url){
14061        this.removeStyleSheet(id);
14062        var ss = doc.createElement("link");
14063        ss.setAttribute("rel", "stylesheet");
14064        ss.setAttribute("type", "text/css");
14065        ss.setAttribute("id", id);
14066        ss.setAttribute("href", url);
14067        doc.getElementsByTagName("head")[0].appendChild(ss);
14068    },
14069    
14070    /**
14071     * Refresh the rule cache if you have dynamically added stylesheets
14072     * @return {Object} An object (hash) of rules indexed by selector
14073     */
14074    refreshCache : function(){
14075        return this.getRules(true);
14076    },
14077
14078    // private
14079    cacheStyleSheet : function(stylesheet){
14080        if(!rules){
14081            rules = {};
14082        }
14083        try{// try catch for cross domain access issue
14084            var ssRules = stylesheet.cssRules || stylesheet.rules;
14085            for(var j = ssRules.length-1; j >= 0; --j){
14086                rules[ssRules[j].selectorText] = ssRules[j];
14087            }
14088        }catch(e){}
14089    },
14090    
14091    /**
14092     * Gets all css rules for the document
14093     * @param {Boolean} refreshCache true to refresh the internal cache
14094     * @return {Object} An object (hash) of rules indexed by selector
14095     */
14096    getRules : function(refreshCache){
14097                 if(rules == null || refreshCache){
14098                         rules = {};
14099                         var ds = doc.styleSheets;
14100                         for(var i =0, len = ds.length; i < len; i++){
14101                             try{
14102                         this.cacheStyleSheet(ds[i]);
14103                     }catch(e){} 
14104                 }
14105                 }
14106                 return rules;
14107         },
14108         
14109         /**
14110     * Gets an an individual CSS rule by selector(s)
14111     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14112     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14113     * @return {CSSRule} The CSS rule or null if one is not found
14114     */
14115    getRule : function(selector, refreshCache){
14116                 var rs = this.getRules(refreshCache);
14117                 if(!(selector instanceof Array)){
14118                     return rs[selector];
14119                 }
14120                 for(var i = 0; i < selector.length; i++){
14121                         if(rs[selector[i]]){
14122                                 return rs[selector[i]];
14123                         }
14124                 }
14125                 return null;
14126         },
14127         
14128         
14129         /**
14130     * Updates a rule property
14131     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14132     * @param {String} property The css property
14133     * @param {String} value The new value for the property
14134     * @return {Boolean} true If a rule was found and updated
14135     */
14136    updateRule : function(selector, property, value){
14137                 if(!(selector instanceof Array)){
14138                         var rule = this.getRule(selector);
14139                         if(rule){
14140                                 rule.style[property.replace(camelRe, camelFn)] = value;
14141                                 return true;
14142                         }
14143                 }else{
14144                         for(var i = 0; i < selector.length; i++){
14145                                 if(this.updateRule(selector[i], property, value)){
14146                                         return true;
14147                                 }
14148                         }
14149                 }
14150                 return false;
14151         }
14152    };   
14153 }();/*
14154  * Based on:
14155  * Ext JS Library 1.1.1
14156  * Copyright(c) 2006-2007, Ext JS, LLC.
14157  *
14158  * Originally Released Under LGPL - original licence link has changed is not relivant.
14159  *
14160  * Fork - LGPL
14161  * <script type="text/javascript">
14162  */
14163
14164  
14165
14166 /**
14167  * @class Roo.util.ClickRepeater
14168  * @extends Roo.util.Observable
14169  * 
14170  * A wrapper class which can be applied to any element. Fires a "click" event while the
14171  * mouse is pressed. The interval between firings may be specified in the config but
14172  * defaults to 10 milliseconds.
14173  * 
14174  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14175  * 
14176  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14177  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14178  * Similar to an autorepeat key delay.
14179  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14180  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14181  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14182  *           "interval" and "delay" are ignored. "immediate" is honored.
14183  * @cfg {Boolean} preventDefault True to prevent the default click event
14184  * @cfg {Boolean} stopDefault True to stop the default click event
14185  * 
14186  * @history
14187  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14188  *     2007-02-02 jvs Renamed to ClickRepeater
14189  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14190  *
14191  *  @constructor
14192  * @param {String/HTMLElement/Element} el The element to listen on
14193  * @param {Object} config
14194  **/
14195 Roo.util.ClickRepeater = function(el, config)
14196 {
14197     this.el = Roo.get(el);
14198     this.el.unselectable();
14199
14200     Roo.apply(this, config);
14201
14202     this.addEvents({
14203     /**
14204      * @event mousedown
14205      * Fires when the mouse button is depressed.
14206      * @param {Roo.util.ClickRepeater} this
14207      */
14208         "mousedown" : true,
14209     /**
14210      * @event click
14211      * Fires on a specified interval during the time the element is pressed.
14212      * @param {Roo.util.ClickRepeater} this
14213      */
14214         "click" : true,
14215     /**
14216      * @event mouseup
14217      * Fires when the mouse key is released.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "mouseup" : true
14221     });
14222
14223     this.el.on("mousedown", this.handleMouseDown, this);
14224     if(this.preventDefault || this.stopDefault){
14225         this.el.on("click", function(e){
14226             if(this.preventDefault){
14227                 e.preventDefault();
14228             }
14229             if(this.stopDefault){
14230                 e.stopEvent();
14231             }
14232         }, this);
14233     }
14234
14235     // allow inline handler
14236     if(this.handler){
14237         this.on("click", this.handler,  this.scope || this);
14238     }
14239
14240     Roo.util.ClickRepeater.superclass.constructor.call(this);
14241 };
14242
14243 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14244     interval : 20,
14245     delay: 250,
14246     preventDefault : true,
14247     stopDefault : false,
14248     timer : 0,
14249
14250     // private
14251     handleMouseDown : function(){
14252         clearTimeout(this.timer);
14253         this.el.blur();
14254         if(this.pressClass){
14255             this.el.addClass(this.pressClass);
14256         }
14257         this.mousedownTime = new Date();
14258
14259         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14260         this.el.on("mouseout", this.handleMouseOut, this);
14261
14262         this.fireEvent("mousedown", this);
14263         this.fireEvent("click", this);
14264         
14265         this.timer = this.click.defer(this.delay || this.interval, this);
14266     },
14267
14268     // private
14269     click : function(){
14270         this.fireEvent("click", this);
14271         this.timer = this.click.defer(this.getInterval(), this);
14272     },
14273
14274     // private
14275     getInterval: function(){
14276         if(!this.accelerate){
14277             return this.interval;
14278         }
14279         var pressTime = this.mousedownTime.getElapsed();
14280         if(pressTime < 500){
14281             return 400;
14282         }else if(pressTime < 1700){
14283             return 320;
14284         }else if(pressTime < 2600){
14285             return 250;
14286         }else if(pressTime < 3500){
14287             return 180;
14288         }else if(pressTime < 4400){
14289             return 140;
14290         }else if(pressTime < 5300){
14291             return 80;
14292         }else if(pressTime < 6200){
14293             return 50;
14294         }else{
14295             return 10;
14296         }
14297     },
14298
14299     // private
14300     handleMouseOut : function(){
14301         clearTimeout(this.timer);
14302         if(this.pressClass){
14303             this.el.removeClass(this.pressClass);
14304         }
14305         this.el.on("mouseover", this.handleMouseReturn, this);
14306     },
14307
14308     // private
14309     handleMouseReturn : function(){
14310         this.el.un("mouseover", this.handleMouseReturn);
14311         if(this.pressClass){
14312             this.el.addClass(this.pressClass);
14313         }
14314         this.click();
14315     },
14316
14317     // private
14318     handleMouseUp : function(){
14319         clearTimeout(this.timer);
14320         this.el.un("mouseover", this.handleMouseReturn);
14321         this.el.un("mouseout", this.handleMouseOut);
14322         Roo.get(document).un("mouseup", this.handleMouseUp);
14323         this.el.removeClass(this.pressClass);
14324         this.fireEvent("mouseup", this);
14325     }
14326 });/*
14327  * Based on:
14328  * Ext JS Library 1.1.1
14329  * Copyright(c) 2006-2007, Ext JS, LLC.
14330  *
14331  * Originally Released Under LGPL - original licence link has changed is not relivant.
14332  *
14333  * Fork - LGPL
14334  * <script type="text/javascript">
14335  */
14336
14337  
14338 /**
14339  * @class Roo.KeyNav
14340  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14341  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14342  * way to implement custom navigation schemes for any UI component.</p>
14343  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14344  * pageUp, pageDown, del, home, end.  Usage:</p>
14345  <pre><code>
14346 var nav = new Roo.KeyNav("my-element", {
14347     "left" : function(e){
14348         this.moveLeft(e.ctrlKey);
14349     },
14350     "right" : function(e){
14351         this.moveRight(e.ctrlKey);
14352     },
14353     "enter" : function(e){
14354         this.save();
14355     },
14356     scope : this
14357 });
14358 </code></pre>
14359  * @constructor
14360  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14361  * @param {Object} config The config
14362  */
14363 Roo.KeyNav = function(el, config){
14364     this.el = Roo.get(el);
14365     Roo.apply(this, config);
14366     if(!this.disabled){
14367         this.disabled = true;
14368         this.enable();
14369     }
14370 };
14371
14372 Roo.KeyNav.prototype = {
14373     /**
14374      * @cfg {Boolean} disabled
14375      * True to disable this KeyNav instance (defaults to false)
14376      */
14377     disabled : false,
14378     /**
14379      * @cfg {String} defaultEventAction
14380      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14381      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14382      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14383      */
14384     defaultEventAction: "stopEvent",
14385     /**
14386      * @cfg {Boolean} forceKeyDown
14387      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14388      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14389      * handle keydown instead of keypress.
14390      */
14391     forceKeyDown : false,
14392
14393     // private
14394     prepareEvent : function(e){
14395         var k = e.getKey();
14396         var h = this.keyToHandler[k];
14397         //if(h && this[h]){
14398         //    e.stopPropagation();
14399         //}
14400         if(Roo.isSafari && h && k >= 37 && k <= 40){
14401             e.stopEvent();
14402         }
14403     },
14404
14405     // private
14406     relay : function(e){
14407         var k = e.getKey();
14408         var h = this.keyToHandler[k];
14409         if(h && this[h]){
14410             if(this.doRelay(e, this[h], h) !== true){
14411                 e[this.defaultEventAction]();
14412             }
14413         }
14414     },
14415
14416     // private
14417     doRelay : function(e, h, hname){
14418         return h.call(this.scope || this, e);
14419     },
14420
14421     // possible handlers
14422     enter : false,
14423     left : false,
14424     right : false,
14425     up : false,
14426     down : false,
14427     tab : false,
14428     esc : false,
14429     pageUp : false,
14430     pageDown : false,
14431     del : false,
14432     home : false,
14433     end : false,
14434
14435     // quick lookup hash
14436     keyToHandler : {
14437         37 : "left",
14438         39 : "right",
14439         38 : "up",
14440         40 : "down",
14441         33 : "pageUp",
14442         34 : "pageDown",
14443         46 : "del",
14444         36 : "home",
14445         35 : "end",
14446         13 : "enter",
14447         27 : "esc",
14448         9  : "tab"
14449     },
14450
14451         /**
14452          * Enable this KeyNav
14453          */
14454         enable: function(){
14455                 if(this.disabled){
14456             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14457             // the EventObject will normalize Safari automatically
14458             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14459                 this.el.on("keydown", this.relay,  this);
14460             }else{
14461                 this.el.on("keydown", this.prepareEvent,  this);
14462                 this.el.on("keypress", this.relay,  this);
14463             }
14464                     this.disabled = false;
14465                 }
14466         },
14467
14468         /**
14469          * Disable this KeyNav
14470          */
14471         disable: function(){
14472                 if(!this.disabled){
14473                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14474                 this.el.un("keydown", this.relay);
14475             }else{
14476                 this.el.un("keydown", this.prepareEvent);
14477                 this.el.un("keypress", this.relay);
14478             }
14479                     this.disabled = true;
14480                 }
14481         }
14482 };/*
14483  * Based on:
14484  * Ext JS Library 1.1.1
14485  * Copyright(c) 2006-2007, Ext JS, LLC.
14486  *
14487  * Originally Released Under LGPL - original licence link has changed is not relivant.
14488  *
14489  * Fork - LGPL
14490  * <script type="text/javascript">
14491  */
14492
14493  
14494 /**
14495  * @class Roo.KeyMap
14496  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14497  * The constructor accepts the same config object as defined by {@link #addBinding}.
14498  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14499  * combination it will call the function with this signature (if the match is a multi-key
14500  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14501  * A KeyMap can also handle a string representation of keys.<br />
14502  * Usage:
14503  <pre><code>
14504 // map one key by key code
14505 var map = new Roo.KeyMap("my-element", {
14506     key: 13, // or Roo.EventObject.ENTER
14507     fn: myHandler,
14508     scope: myObject
14509 });
14510
14511 // map multiple keys to one action by string
14512 var map = new Roo.KeyMap("my-element", {
14513     key: "a\r\n\t",
14514     fn: myHandler,
14515     scope: myObject
14516 });
14517
14518 // map multiple keys to multiple actions by strings and array of codes
14519 var map = new Roo.KeyMap("my-element", [
14520     {
14521         key: [10,13],
14522         fn: function(){ alert("Return was pressed"); }
14523     }, {
14524         key: "abc",
14525         fn: function(){ alert('a, b or c was pressed'); }
14526     }, {
14527         key: "\t",
14528         ctrl:true,
14529         shift:true,
14530         fn: function(){ alert('Control + shift + tab was pressed.'); }
14531     }
14532 ]);
14533 </code></pre>
14534  * <b>Note: A KeyMap starts enabled</b>
14535  * @constructor
14536  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14537  * @param {Object} config The config (see {@link #addBinding})
14538  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14539  */
14540 Roo.KeyMap = function(el, config, eventName){
14541     this.el  = Roo.get(el);
14542     this.eventName = eventName || "keydown";
14543     this.bindings = [];
14544     if(config){
14545         this.addBinding(config);
14546     }
14547     this.enable();
14548 };
14549
14550 Roo.KeyMap.prototype = {
14551     /**
14552      * True to stop the event from bubbling and prevent the default browser action if the
14553      * key was handled by the KeyMap (defaults to false)
14554      * @type Boolean
14555      */
14556     stopEvent : false,
14557
14558     /**
14559      * Add a new binding to this KeyMap. The following config object properties are supported:
14560      * <pre>
14561 Property    Type             Description
14562 ----------  ---------------  ----------------------------------------------------------------------
14563 key         String/Array     A single keycode or an array of keycodes to handle
14564 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14565 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14566 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14567 fn          Function         The function to call when KeyMap finds the expected key combination
14568 scope       Object           The scope of the callback function
14569 </pre>
14570      *
14571      * Usage:
14572      * <pre><code>
14573 // Create a KeyMap
14574 var map = new Roo.KeyMap(document, {
14575     key: Roo.EventObject.ENTER,
14576     fn: handleKey,
14577     scope: this
14578 });
14579
14580 //Add a new binding to the existing KeyMap later
14581 map.addBinding({
14582     key: 'abc',
14583     shift: true,
14584     fn: handleKey,
14585     scope: this
14586 });
14587 </code></pre>
14588      * @param {Object/Array} config A single KeyMap config or an array of configs
14589      */
14590         addBinding : function(config){
14591         if(config instanceof Array){
14592             for(var i = 0, len = config.length; i < len; i++){
14593                 this.addBinding(config[i]);
14594             }
14595             return;
14596         }
14597         var keyCode = config.key,
14598             shift = config.shift, 
14599             ctrl = config.ctrl, 
14600             alt = config.alt,
14601             fn = config.fn,
14602             scope = config.scope;
14603         if(typeof keyCode == "string"){
14604             var ks = [];
14605             var keyString = keyCode.toUpperCase();
14606             for(var j = 0, len = keyString.length; j < len; j++){
14607                 ks.push(keyString.charCodeAt(j));
14608             }
14609             keyCode = ks;
14610         }
14611         var keyArray = keyCode instanceof Array;
14612         var handler = function(e){
14613             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14614                 var k = e.getKey();
14615                 if(keyArray){
14616                     for(var i = 0, len = keyCode.length; i < len; i++){
14617                         if(keyCode[i] == k){
14618                           if(this.stopEvent){
14619                               e.stopEvent();
14620                           }
14621                           fn.call(scope || window, k, e);
14622                           return;
14623                         }
14624                     }
14625                 }else{
14626                     if(k == keyCode){
14627                         if(this.stopEvent){
14628                            e.stopEvent();
14629                         }
14630                         fn.call(scope || window, k, e);
14631                     }
14632                 }
14633             }
14634         };
14635         this.bindings.push(handler);  
14636         },
14637
14638     /**
14639      * Shorthand for adding a single key listener
14640      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14641      * following options:
14642      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14643      * @param {Function} fn The function to call
14644      * @param {Object} scope (optional) The scope of the function
14645      */
14646     on : function(key, fn, scope){
14647         var keyCode, shift, ctrl, alt;
14648         if(typeof key == "object" && !(key instanceof Array)){
14649             keyCode = key.key;
14650             shift = key.shift;
14651             ctrl = key.ctrl;
14652             alt = key.alt;
14653         }else{
14654             keyCode = key;
14655         }
14656         this.addBinding({
14657             key: keyCode,
14658             shift: shift,
14659             ctrl: ctrl,
14660             alt: alt,
14661             fn: fn,
14662             scope: scope
14663         })
14664     },
14665
14666     // private
14667     handleKeyDown : function(e){
14668             if(this.enabled){ //just in case
14669             var b = this.bindings;
14670             for(var i = 0, len = b.length; i < len; i++){
14671                 b[i].call(this, e);
14672             }
14673             }
14674         },
14675         
14676         /**
14677          * Returns true if this KeyMap is enabled
14678          * @return {Boolean} 
14679          */
14680         isEnabled : function(){
14681             return this.enabled;  
14682         },
14683         
14684         /**
14685          * Enables this KeyMap
14686          */
14687         enable: function(){
14688                 if(!this.enabled){
14689                     this.el.on(this.eventName, this.handleKeyDown, this);
14690                     this.enabled = true;
14691                 }
14692         },
14693
14694         /**
14695          * Disable this KeyMap
14696          */
14697         disable: function(){
14698                 if(this.enabled){
14699                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14700                     this.enabled = false;
14701                 }
14702         }
14703 };/*
14704  * Based on:
14705  * Ext JS Library 1.1.1
14706  * Copyright(c) 2006-2007, Ext JS, LLC.
14707  *
14708  * Originally Released Under LGPL - original licence link has changed is not relivant.
14709  *
14710  * Fork - LGPL
14711  * <script type="text/javascript">
14712  */
14713
14714  
14715 /**
14716  * @class Roo.util.TextMetrics
14717  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14718  * wide, in pixels, a given block of text will be.
14719  * @singleton
14720  */
14721 Roo.util.TextMetrics = function(){
14722     var shared;
14723     return {
14724         /**
14725          * Measures the size of the specified text
14726          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14727          * that can affect the size of the rendered text
14728          * @param {String} text The text to measure
14729          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14730          * in order to accurately measure the text height
14731          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14732          */
14733         measure : function(el, text, fixedWidth){
14734             if(!shared){
14735                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14736             }
14737             shared.bind(el);
14738             shared.setFixedWidth(fixedWidth || 'auto');
14739             return shared.getSize(text);
14740         },
14741
14742         /**
14743          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14744          * the overhead of multiple calls to initialize the style properties on each measurement.
14745          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14746          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14747          * in order to accurately measure the text height
14748          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14749          */
14750         createInstance : function(el, fixedWidth){
14751             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14752         }
14753     };
14754 }();
14755
14756  
14757
14758 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14759     var ml = new Roo.Element(document.createElement('div'));
14760     document.body.appendChild(ml.dom);
14761     ml.position('absolute');
14762     ml.setLeftTop(-1000, -1000);
14763     ml.hide();
14764
14765     if(fixedWidth){
14766         ml.setWidth(fixedWidth);
14767     }
14768      
14769     var instance = {
14770         /**
14771          * Returns the size of the specified text based on the internal element's style and width properties
14772          * @memberOf Roo.util.TextMetrics.Instance#
14773          * @param {String} text The text to measure
14774          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14775          */
14776         getSize : function(text){
14777             ml.update(text);
14778             var s = ml.getSize();
14779             ml.update('');
14780             return s;
14781         },
14782
14783         /**
14784          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14785          * that can affect the size of the rendered text
14786          * @memberOf Roo.util.TextMetrics.Instance#
14787          * @param {String/HTMLElement} el The element, dom node or id
14788          */
14789         bind : function(el){
14790             ml.setStyle(
14791                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14792             );
14793         },
14794
14795         /**
14796          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14797          * to set a fixed width in order to accurately measure the text height.
14798          * @memberOf Roo.util.TextMetrics.Instance#
14799          * @param {Number} width The width to set on the element
14800          */
14801         setFixedWidth : function(width){
14802             ml.setWidth(width);
14803         },
14804
14805         /**
14806          * Returns the measured width of the specified text
14807          * @memberOf Roo.util.TextMetrics.Instance#
14808          * @param {String} text The text to measure
14809          * @return {Number} width The width in pixels
14810          */
14811         getWidth : function(text){
14812             ml.dom.style.width = 'auto';
14813             return this.getSize(text).width;
14814         },
14815
14816         /**
14817          * Returns the measured height of the specified text.  For multiline text, be sure to call
14818          * {@link #setFixedWidth} if necessary.
14819          * @memberOf Roo.util.TextMetrics.Instance#
14820          * @param {String} text The text to measure
14821          * @return {Number} height The height in pixels
14822          */
14823         getHeight : function(text){
14824             return this.getSize(text).height;
14825         }
14826     };
14827
14828     instance.bind(bindTo);
14829
14830     return instance;
14831 };
14832
14833 // backwards compat
14834 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14835  * Based on:
14836  * Ext JS Library 1.1.1
14837  * Copyright(c) 2006-2007, Ext JS, LLC.
14838  *
14839  * Originally Released Under LGPL - original licence link has changed is not relivant.
14840  *
14841  * Fork - LGPL
14842  * <script type="text/javascript">
14843  */
14844
14845 /**
14846  * @class Roo.state.Provider
14847  * Abstract base class for state provider implementations. This class provides methods
14848  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14849  * Provider interface.
14850  */
14851 Roo.state.Provider = function(){
14852     /**
14853      * @event statechange
14854      * Fires when a state change occurs.
14855      * @param {Provider} this This state provider
14856      * @param {String} key The state key which was changed
14857      * @param {String} value The encoded value for the state
14858      */
14859     this.addEvents({
14860         "statechange": true
14861     });
14862     this.state = {};
14863     Roo.state.Provider.superclass.constructor.call(this);
14864 };
14865 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14866     /**
14867      * Returns the current value for a key
14868      * @param {String} name The key name
14869      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14870      * @return {Mixed} The state data
14871      */
14872     get : function(name, defaultValue){
14873         return typeof this.state[name] == "undefined" ?
14874             defaultValue : this.state[name];
14875     },
14876     
14877     /**
14878      * Clears a value from the state
14879      * @param {String} name The key name
14880      */
14881     clear : function(name){
14882         delete this.state[name];
14883         this.fireEvent("statechange", this, name, null);
14884     },
14885     
14886     /**
14887      * Sets the value for a key
14888      * @param {String} name The key name
14889      * @param {Mixed} value The value to set
14890      */
14891     set : function(name, value){
14892         this.state[name] = value;
14893         this.fireEvent("statechange", this, name, value);
14894     },
14895     
14896     /**
14897      * Decodes a string previously encoded with {@link #encodeValue}.
14898      * @param {String} value The value to decode
14899      * @return {Mixed} The decoded value
14900      */
14901     decodeValue : function(cookie){
14902         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14903         var matches = re.exec(unescape(cookie));
14904         if(!matches || !matches[1]) {
14905             return; // non state cookie
14906         }
14907         var type = matches[1];
14908         var v = matches[2];
14909         switch(type){
14910             case "n":
14911                 return parseFloat(v);
14912             case "d":
14913                 return new Date(Date.parse(v));
14914             case "b":
14915                 return (v == "1");
14916             case "a":
14917                 var all = [];
14918                 var values = v.split("^");
14919                 for(var i = 0, len = values.length; i < len; i++){
14920                     all.push(this.decodeValue(values[i]));
14921                 }
14922                 return all;
14923            case "o":
14924                 var all = {};
14925                 var values = v.split("^");
14926                 for(var i = 0, len = values.length; i < len; i++){
14927                     var kv = values[i].split("=");
14928                     all[kv[0]] = this.decodeValue(kv[1]);
14929                 }
14930                 return all;
14931            default:
14932                 return v;
14933         }
14934     },
14935     
14936     /**
14937      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14938      * @param {Mixed} value The value to encode
14939      * @return {String} The encoded value
14940      */
14941     encodeValue : function(v){
14942         var enc;
14943         if(typeof v == "number"){
14944             enc = "n:" + v;
14945         }else if(typeof v == "boolean"){
14946             enc = "b:" + (v ? "1" : "0");
14947         }else if(v instanceof Date){
14948             enc = "d:" + v.toGMTString();
14949         }else if(v instanceof Array){
14950             var flat = "";
14951             for(var i = 0, len = v.length; i < len; i++){
14952                 flat += this.encodeValue(v[i]);
14953                 if(i != len-1) {
14954                     flat += "^";
14955                 }
14956             }
14957             enc = "a:" + flat;
14958         }else if(typeof v == "object"){
14959             var flat = "";
14960             for(var key in v){
14961                 if(typeof v[key] != "function"){
14962                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14963                 }
14964             }
14965             enc = "o:" + flat.substring(0, flat.length-1);
14966         }else{
14967             enc = "s:" + v;
14968         }
14969         return escape(enc);        
14970     }
14971 });
14972
14973 /*
14974  * Based on:
14975  * Ext JS Library 1.1.1
14976  * Copyright(c) 2006-2007, Ext JS, LLC.
14977  *
14978  * Originally Released Under LGPL - original licence link has changed is not relivant.
14979  *
14980  * Fork - LGPL
14981  * <script type="text/javascript">
14982  */
14983 /**
14984  * @class Roo.state.Manager
14985  * This is the global state manager. By default all components that are "state aware" check this class
14986  * for state information if you don't pass them a custom state provider. In order for this class
14987  * to be useful, it must be initialized with a provider when your application initializes.
14988  <pre><code>
14989 // in your initialization function
14990 init : function(){
14991    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14992    ...
14993    // supposed you have a {@link Roo.BorderLayout}
14994    var layout = new Roo.BorderLayout(...);
14995    layout.restoreState();
14996    // or a {Roo.BasicDialog}
14997    var dialog = new Roo.BasicDialog(...);
14998    dialog.restoreState();
14999  </code></pre>
15000  * @singleton
15001  */
15002 Roo.state.Manager = function(){
15003     var provider = new Roo.state.Provider();
15004     
15005     return {
15006         /**
15007          * Configures the default state provider for your application
15008          * @param {Provider} stateProvider The state provider to set
15009          */
15010         setProvider : function(stateProvider){
15011             provider = stateProvider;
15012         },
15013         
15014         /**
15015          * Returns the current value for a key
15016          * @param {String} name The key name
15017          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15018          * @return {Mixed} The state data
15019          */
15020         get : function(key, defaultValue){
15021             return provider.get(key, defaultValue);
15022         },
15023         
15024         /**
15025          * Sets the value for a key
15026          * @param {String} name The key name
15027          * @param {Mixed} value The state data
15028          */
15029          set : function(key, value){
15030             provider.set(key, value);
15031         },
15032         
15033         /**
15034          * Clears a value from the state
15035          * @param {String} name The key name
15036          */
15037         clear : function(key){
15038             provider.clear(key);
15039         },
15040         
15041         /**
15042          * Gets the currently configured state provider
15043          * @return {Provider} The state provider
15044          */
15045         getProvider : function(){
15046             return provider;
15047         }
15048     };
15049 }();
15050 /*
15051  * Based on:
15052  * Ext JS Library 1.1.1
15053  * Copyright(c) 2006-2007, Ext JS, LLC.
15054  *
15055  * Originally Released Under LGPL - original licence link has changed is not relivant.
15056  *
15057  * Fork - LGPL
15058  * <script type="text/javascript">
15059  */
15060 /**
15061  * @class Roo.state.CookieProvider
15062  * @extends Roo.state.Provider
15063  * The default Provider implementation which saves state via cookies.
15064  * <br />Usage:
15065  <pre><code>
15066    var cp = new Roo.state.CookieProvider({
15067        path: "/cgi-bin/",
15068        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15069        domain: "roojs.com"
15070    })
15071    Roo.state.Manager.setProvider(cp);
15072  </code></pre>
15073  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15074  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15075  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15076  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15077  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15078  * domain the page is running on including the 'www' like 'www.roojs.com')
15079  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15080  * @constructor
15081  * Create a new CookieProvider
15082  * @param {Object} config The configuration object
15083  */
15084 Roo.state.CookieProvider = function(config){
15085     Roo.state.CookieProvider.superclass.constructor.call(this);
15086     this.path = "/";
15087     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15088     this.domain = null;
15089     this.secure = false;
15090     Roo.apply(this, config);
15091     this.state = this.readCookies();
15092 };
15093
15094 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15095     // private
15096     set : function(name, value){
15097         if(typeof value == "undefined" || value === null){
15098             this.clear(name);
15099             return;
15100         }
15101         this.setCookie(name, value);
15102         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15103     },
15104
15105     // private
15106     clear : function(name){
15107         this.clearCookie(name);
15108         Roo.state.CookieProvider.superclass.clear.call(this, name);
15109     },
15110
15111     // private
15112     readCookies : function(){
15113         var cookies = {};
15114         var c = document.cookie + ";";
15115         var re = /\s?(.*?)=(.*?);/g;
15116         var matches;
15117         while((matches = re.exec(c)) != null){
15118             var name = matches[1];
15119             var value = matches[2];
15120             if(name && name.substring(0,3) == "ys-"){
15121                 cookies[name.substr(3)] = this.decodeValue(value);
15122             }
15123         }
15124         return cookies;
15125     },
15126
15127     // private
15128     setCookie : function(name, value){
15129         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15130            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15131            ((this.path == null) ? "" : ("; path=" + this.path)) +
15132            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15133            ((this.secure == true) ? "; secure" : "");
15134     },
15135
15136     // private
15137     clearCookie : function(name){
15138         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15139            ((this.path == null) ? "" : ("; path=" + this.path)) +
15140            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15141            ((this.secure == true) ? "; secure" : "");
15142     }
15143 });/*
15144  * Based on:
15145  * Ext JS Library 1.1.1
15146  * Copyright(c) 2006-2007, Ext JS, LLC.
15147  *
15148  * Originally Released Under LGPL - original licence link has changed is not relivant.
15149  *
15150  * Fork - LGPL
15151  * <script type="text/javascript">
15152  */
15153  
15154
15155 /**
15156  * @class Roo.ComponentMgr
15157  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15158  * @singleton
15159  */
15160 Roo.ComponentMgr = function(){
15161     var all = new Roo.util.MixedCollection();
15162
15163     return {
15164         /**
15165          * Registers a component.
15166          * @param {Roo.Component} c The component
15167          */
15168         register : function(c){
15169             all.add(c);
15170         },
15171
15172         /**
15173          * Unregisters a component.
15174          * @param {Roo.Component} c The component
15175          */
15176         unregister : function(c){
15177             all.remove(c);
15178         },
15179
15180         /**
15181          * Returns a component by id
15182          * @param {String} id The component id
15183          */
15184         get : function(id){
15185             return all.get(id);
15186         },
15187
15188         /**
15189          * Registers a function that will be called when a specified component is added to ComponentMgr
15190          * @param {String} id The component id
15191          * @param {Funtction} fn The callback function
15192          * @param {Object} scope The scope of the callback
15193          */
15194         onAvailable : function(id, fn, scope){
15195             all.on("add", function(index, o){
15196                 if(o.id == id){
15197                     fn.call(scope || o, o);
15198                     all.un("add", fn, scope);
15199                 }
15200             });
15201         }
15202     };
15203 }();/*
15204  * Based on:
15205  * Ext JS Library 1.1.1
15206  * Copyright(c) 2006-2007, Ext JS, LLC.
15207  *
15208  * Originally Released Under LGPL - original licence link has changed is not relivant.
15209  *
15210  * Fork - LGPL
15211  * <script type="text/javascript">
15212  */
15213  
15214 /**
15215  * @class Roo.Component
15216  * @extends Roo.util.Observable
15217  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15218  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15219  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15220  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15221  * All visual components (widgets) that require rendering into a layout should subclass Component.
15222  * @constructor
15223  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15224  * 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
15225  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15226  */
15227 Roo.Component = function(config){
15228     config = config || {};
15229     if(config.tagName || config.dom || typeof config == "string"){ // element object
15230         config = {el: config, id: config.id || config};
15231     }
15232     this.initialConfig = config;
15233
15234     Roo.apply(this, config);
15235     this.addEvents({
15236         /**
15237          * @event disable
15238          * Fires after the component is disabled.
15239              * @param {Roo.Component} this
15240              */
15241         disable : true,
15242         /**
15243          * @event enable
15244          * Fires after the component is enabled.
15245              * @param {Roo.Component} this
15246              */
15247         enable : true,
15248         /**
15249          * @event beforeshow
15250          * Fires before the component is shown.  Return false to stop the show.
15251              * @param {Roo.Component} this
15252              */
15253         beforeshow : true,
15254         /**
15255          * @event show
15256          * Fires after the component is shown.
15257              * @param {Roo.Component} this
15258              */
15259         show : true,
15260         /**
15261          * @event beforehide
15262          * Fires before the component is hidden. Return false to stop the hide.
15263              * @param {Roo.Component} this
15264              */
15265         beforehide : true,
15266         /**
15267          * @event hide
15268          * Fires after the component is hidden.
15269              * @param {Roo.Component} this
15270              */
15271         hide : true,
15272         /**
15273          * @event beforerender
15274          * Fires before the component is rendered. Return false to stop the render.
15275              * @param {Roo.Component} this
15276              */
15277         beforerender : true,
15278         /**
15279          * @event render
15280          * Fires after the component is rendered.
15281              * @param {Roo.Component} this
15282              */
15283         render : true,
15284         /**
15285          * @event beforedestroy
15286          * Fires before the component is destroyed. Return false to stop the destroy.
15287              * @param {Roo.Component} this
15288              */
15289         beforedestroy : true,
15290         /**
15291          * @event destroy
15292          * Fires after the component is destroyed.
15293              * @param {Roo.Component} this
15294              */
15295         destroy : true
15296     });
15297     if(!this.id){
15298         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15299     }
15300     Roo.ComponentMgr.register(this);
15301     Roo.Component.superclass.constructor.call(this);
15302     this.initComponent();
15303     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15304         this.render(this.renderTo);
15305         delete this.renderTo;
15306     }
15307 };
15308
15309 /** @private */
15310 Roo.Component.AUTO_ID = 1000;
15311
15312 Roo.extend(Roo.Component, Roo.util.Observable, {
15313     /**
15314      * @scope Roo.Component.prototype
15315      * @type {Boolean}
15316      * true if this component is hidden. Read-only.
15317      */
15318     hidden : false,
15319     /**
15320      * @type {Boolean}
15321      * true if this component is disabled. Read-only.
15322      */
15323     disabled : false,
15324     /**
15325      * @type {Boolean}
15326      * true if this component has been rendered. Read-only.
15327      */
15328     rendered : false,
15329     
15330     /** @cfg {String} disableClass
15331      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15332      */
15333     disabledClass : "x-item-disabled",
15334         /** @cfg {Boolean} allowDomMove
15335          * Whether the component can move the Dom node when rendering (defaults to true).
15336          */
15337     allowDomMove : true,
15338     /** @cfg {String} hideMode (display|visibility)
15339      * How this component should hidden. Supported values are
15340      * "visibility" (css visibility), "offsets" (negative offset position) and
15341      * "display" (css display) - defaults to "display".
15342      */
15343     hideMode: 'display',
15344
15345     /** @private */
15346     ctype : "Roo.Component",
15347
15348     /**
15349      * @cfg {String} actionMode 
15350      * which property holds the element that used for  hide() / show() / disable() / enable()
15351      * default is 'el' 
15352      */
15353     actionMode : "el",
15354
15355     /** @private */
15356     getActionEl : function(){
15357         return this[this.actionMode];
15358     },
15359
15360     initComponent : Roo.emptyFn,
15361     /**
15362      * If this is a lazy rendering component, render it to its container element.
15363      * @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.
15364      */
15365     render : function(container, position){
15366         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15367             if(!container && this.el){
15368                 this.el = Roo.get(this.el);
15369                 container = this.el.dom.parentNode;
15370                 this.allowDomMove = false;
15371             }
15372             this.container = Roo.get(container);
15373             this.rendered = true;
15374             if(position !== undefined){
15375                 if(typeof position == 'number'){
15376                     position = this.container.dom.childNodes[position];
15377                 }else{
15378                     position = Roo.getDom(position);
15379                 }
15380             }
15381             this.onRender(this.container, position || null);
15382             if(this.cls){
15383                 this.el.addClass(this.cls);
15384                 delete this.cls;
15385             }
15386             if(this.style){
15387                 this.el.applyStyles(this.style);
15388                 delete this.style;
15389             }
15390             this.fireEvent("render", this);
15391             this.afterRender(this.container);
15392             if(this.hidden){
15393                 this.hide();
15394             }
15395             if(this.disabled){
15396                 this.disable();
15397             }
15398         }
15399         return this;
15400     },
15401
15402     /** @private */
15403     // default function is not really useful
15404     onRender : function(ct, position){
15405         if(this.el){
15406             this.el = Roo.get(this.el);
15407             if(this.allowDomMove !== false){
15408                 ct.dom.insertBefore(this.el.dom, position);
15409             }
15410         }
15411     },
15412
15413     /** @private */
15414     getAutoCreate : function(){
15415         var cfg = typeof this.autoCreate == "object" ?
15416                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15417         if(this.id && !cfg.id){
15418             cfg.id = this.id;
15419         }
15420         return cfg;
15421     },
15422
15423     /** @private */
15424     afterRender : Roo.emptyFn,
15425
15426     /**
15427      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15428      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15429      */
15430     destroy : function(){
15431         if(this.fireEvent("beforedestroy", this) !== false){
15432             this.purgeListeners();
15433             this.beforeDestroy();
15434             if(this.rendered){
15435                 this.el.removeAllListeners();
15436                 this.el.remove();
15437                 if(this.actionMode == "container"){
15438                     this.container.remove();
15439                 }
15440             }
15441             this.onDestroy();
15442             Roo.ComponentMgr.unregister(this);
15443             this.fireEvent("destroy", this);
15444         }
15445     },
15446
15447         /** @private */
15448     beforeDestroy : function(){
15449
15450     },
15451
15452         /** @private */
15453         onDestroy : function(){
15454
15455     },
15456
15457     /**
15458      * Returns the underlying {@link Roo.Element}.
15459      * @return {Roo.Element} The element
15460      */
15461     getEl : function(){
15462         return this.el;
15463     },
15464
15465     /**
15466      * Returns the id of this component.
15467      * @return {String}
15468      */
15469     getId : function(){
15470         return this.id;
15471     },
15472
15473     /**
15474      * Try to focus this component.
15475      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15476      * @return {Roo.Component} this
15477      */
15478     focus : function(selectText){
15479         if(this.rendered){
15480             this.el.focus();
15481             if(selectText === true){
15482                 this.el.dom.select();
15483             }
15484         }
15485         return this;
15486     },
15487
15488     /** @private */
15489     blur : function(){
15490         if(this.rendered){
15491             this.el.blur();
15492         }
15493         return this;
15494     },
15495
15496     /**
15497      * Disable this component.
15498      * @return {Roo.Component} this
15499      */
15500     disable : function(){
15501         if(this.rendered){
15502             this.onDisable();
15503         }
15504         this.disabled = true;
15505         this.fireEvent("disable", this);
15506         return this;
15507     },
15508
15509         // private
15510     onDisable : function(){
15511         this.getActionEl().addClass(this.disabledClass);
15512         this.el.dom.disabled = true;
15513     },
15514
15515     /**
15516      * Enable this component.
15517      * @return {Roo.Component} this
15518      */
15519     enable : function(){
15520         if(this.rendered){
15521             this.onEnable();
15522         }
15523         this.disabled = false;
15524         this.fireEvent("enable", this);
15525         return this;
15526     },
15527
15528         // private
15529     onEnable : function(){
15530         this.getActionEl().removeClass(this.disabledClass);
15531         this.el.dom.disabled = false;
15532     },
15533
15534     /**
15535      * Convenience function for setting disabled/enabled by boolean.
15536      * @param {Boolean} disabled
15537      */
15538     setDisabled : function(disabled){
15539         this[disabled ? "disable" : "enable"]();
15540     },
15541
15542     /**
15543      * Show this component.
15544      * @return {Roo.Component} this
15545      */
15546     show: function(){
15547         if(this.fireEvent("beforeshow", this) !== false){
15548             this.hidden = false;
15549             if(this.rendered){
15550                 this.onShow();
15551             }
15552             this.fireEvent("show", this);
15553         }
15554         return this;
15555     },
15556
15557     // private
15558     onShow : function(){
15559         var ae = this.getActionEl();
15560         if(this.hideMode == 'visibility'){
15561             ae.dom.style.visibility = "visible";
15562         }else if(this.hideMode == 'offsets'){
15563             ae.removeClass('x-hidden');
15564         }else{
15565             ae.dom.style.display = "";
15566         }
15567     },
15568
15569     /**
15570      * Hide this component.
15571      * @return {Roo.Component} this
15572      */
15573     hide: function(){
15574         if(this.fireEvent("beforehide", this) !== false){
15575             this.hidden = true;
15576             if(this.rendered){
15577                 this.onHide();
15578             }
15579             this.fireEvent("hide", this);
15580         }
15581         return this;
15582     },
15583
15584     // private
15585     onHide : function(){
15586         var ae = this.getActionEl();
15587         if(this.hideMode == 'visibility'){
15588             ae.dom.style.visibility = "hidden";
15589         }else if(this.hideMode == 'offsets'){
15590             ae.addClass('x-hidden');
15591         }else{
15592             ae.dom.style.display = "none";
15593         }
15594     },
15595
15596     /**
15597      * Convenience function to hide or show this component by boolean.
15598      * @param {Boolean} visible True to show, false to hide
15599      * @return {Roo.Component} this
15600      */
15601     setVisible: function(visible){
15602         if(visible) {
15603             this.show();
15604         }else{
15605             this.hide();
15606         }
15607         return this;
15608     },
15609
15610     /**
15611      * Returns true if this component is visible.
15612      */
15613     isVisible : function(){
15614         return this.getActionEl().isVisible();
15615     },
15616
15617     cloneConfig : function(overrides){
15618         overrides = overrides || {};
15619         var id = overrides.id || Roo.id();
15620         var cfg = Roo.applyIf(overrides, this.initialConfig);
15621         cfg.id = id; // prevent dup id
15622         return new this.constructor(cfg);
15623     }
15624 });/*
15625  * Based on:
15626  * Ext JS Library 1.1.1
15627  * Copyright(c) 2006-2007, Ext JS, LLC.
15628  *
15629  * Originally Released Under LGPL - original licence link has changed is not relivant.
15630  *
15631  * Fork - LGPL
15632  * <script type="text/javascript">
15633  */
15634
15635 /**
15636  * @class Roo.BoxComponent
15637  * @extends Roo.Component
15638  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15639  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15640  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15641  * layout containers.
15642  * @constructor
15643  * @param {Roo.Element/String/Object} config The configuration options.
15644  */
15645 Roo.BoxComponent = function(config){
15646     Roo.Component.call(this, config);
15647     this.addEvents({
15648         /**
15649          * @event resize
15650          * Fires after the component is resized.
15651              * @param {Roo.Component} this
15652              * @param {Number} adjWidth The box-adjusted width that was set
15653              * @param {Number} adjHeight The box-adjusted height that was set
15654              * @param {Number} rawWidth The width that was originally specified
15655              * @param {Number} rawHeight The height that was originally specified
15656              */
15657         resize : true,
15658         /**
15659          * @event move
15660          * Fires after the component is moved.
15661              * @param {Roo.Component} this
15662              * @param {Number} x The new x position
15663              * @param {Number} y The new y position
15664              */
15665         move : true
15666     });
15667 };
15668
15669 Roo.extend(Roo.BoxComponent, Roo.Component, {
15670     // private, set in afterRender to signify that the component has been rendered
15671     boxReady : false,
15672     // private, used to defer height settings to subclasses
15673     deferHeight: false,
15674     /** @cfg {Number} width
15675      * width (optional) size of component
15676      */
15677      /** @cfg {Number} height
15678      * height (optional) size of component
15679      */
15680      
15681     /**
15682      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15683      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15684      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15685      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15686      * @return {Roo.BoxComponent} this
15687      */
15688     setSize : function(w, h){
15689         // support for standard size objects
15690         if(typeof w == 'object'){
15691             h = w.height;
15692             w = w.width;
15693         }
15694         // not rendered
15695         if(!this.boxReady){
15696             this.width = w;
15697             this.height = h;
15698             return this;
15699         }
15700
15701         // prevent recalcs when not needed
15702         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15703             return this;
15704         }
15705         this.lastSize = {width: w, height: h};
15706
15707         var adj = this.adjustSize(w, h);
15708         var aw = adj.width, ah = adj.height;
15709         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15710             var rz = this.getResizeEl();
15711             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15712                 rz.setSize(aw, ah);
15713             }else if(!this.deferHeight && ah !== undefined){
15714                 rz.setHeight(ah);
15715             }else if(aw !== undefined){
15716                 rz.setWidth(aw);
15717             }
15718             this.onResize(aw, ah, w, h);
15719             this.fireEvent('resize', this, aw, ah, w, h);
15720         }
15721         return this;
15722     },
15723
15724     /**
15725      * Gets the current size of the component's underlying element.
15726      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15727      */
15728     getSize : function(){
15729         return this.el.getSize();
15730     },
15731
15732     /**
15733      * Gets the current XY position of the component's underlying element.
15734      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15735      * @return {Array} The XY position of the element (e.g., [100, 200])
15736      */
15737     getPosition : function(local){
15738         if(local === true){
15739             return [this.el.getLeft(true), this.el.getTop(true)];
15740         }
15741         return this.xy || this.el.getXY();
15742     },
15743
15744     /**
15745      * Gets the current box measurements of the component's underlying element.
15746      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15747      * @returns {Object} box An object in the format {x, y, width, height}
15748      */
15749     getBox : function(local){
15750         var s = this.el.getSize();
15751         if(local){
15752             s.x = this.el.getLeft(true);
15753             s.y = this.el.getTop(true);
15754         }else{
15755             var xy = this.xy || this.el.getXY();
15756             s.x = xy[0];
15757             s.y = xy[1];
15758         }
15759         return s;
15760     },
15761
15762     /**
15763      * Sets the current box measurements of the component's underlying element.
15764      * @param {Object} box An object in the format {x, y, width, height}
15765      * @returns {Roo.BoxComponent} this
15766      */
15767     updateBox : function(box){
15768         this.setSize(box.width, box.height);
15769         this.setPagePosition(box.x, box.y);
15770         return this;
15771     },
15772
15773     // protected
15774     getResizeEl : function(){
15775         return this.resizeEl || this.el;
15776     },
15777
15778     // protected
15779     getPositionEl : function(){
15780         return this.positionEl || this.el;
15781     },
15782
15783     /**
15784      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15785      * This method fires the move event.
15786      * @param {Number} left The new left
15787      * @param {Number} top The new top
15788      * @returns {Roo.BoxComponent} this
15789      */
15790     setPosition : function(x, y){
15791         this.x = x;
15792         this.y = y;
15793         if(!this.boxReady){
15794             return this;
15795         }
15796         var adj = this.adjustPosition(x, y);
15797         var ax = adj.x, ay = adj.y;
15798
15799         var el = this.getPositionEl();
15800         if(ax !== undefined || ay !== undefined){
15801             if(ax !== undefined && ay !== undefined){
15802                 el.setLeftTop(ax, ay);
15803             }else if(ax !== undefined){
15804                 el.setLeft(ax);
15805             }else if(ay !== undefined){
15806                 el.setTop(ay);
15807             }
15808             this.onPosition(ax, ay);
15809             this.fireEvent('move', this, ax, ay);
15810         }
15811         return this;
15812     },
15813
15814     /**
15815      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15816      * This method fires the move event.
15817      * @param {Number} x The new x position
15818      * @param {Number} y The new y position
15819      * @returns {Roo.BoxComponent} this
15820      */
15821     setPagePosition : function(x, y){
15822         this.pageX = x;
15823         this.pageY = y;
15824         if(!this.boxReady){
15825             return;
15826         }
15827         if(x === undefined || y === undefined){ // cannot translate undefined points
15828             return;
15829         }
15830         var p = this.el.translatePoints(x, y);
15831         this.setPosition(p.left, p.top);
15832         return this;
15833     },
15834
15835     // private
15836     onRender : function(ct, position){
15837         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15838         if(this.resizeEl){
15839             this.resizeEl = Roo.get(this.resizeEl);
15840         }
15841         if(this.positionEl){
15842             this.positionEl = Roo.get(this.positionEl);
15843         }
15844     },
15845
15846     // private
15847     afterRender : function(){
15848         Roo.BoxComponent.superclass.afterRender.call(this);
15849         this.boxReady = true;
15850         this.setSize(this.width, this.height);
15851         if(this.x || this.y){
15852             this.setPosition(this.x, this.y);
15853         }
15854         if(this.pageX || this.pageY){
15855             this.setPagePosition(this.pageX, this.pageY);
15856         }
15857     },
15858
15859     /**
15860      * Force the component's size to recalculate based on the underlying element's current height and width.
15861      * @returns {Roo.BoxComponent} this
15862      */
15863     syncSize : function(){
15864         delete this.lastSize;
15865         this.setSize(this.el.getWidth(), this.el.getHeight());
15866         return this;
15867     },
15868
15869     /**
15870      * Called after the component is resized, this method is empty by default but can be implemented by any
15871      * subclass that needs to perform custom logic after a resize occurs.
15872      * @param {Number} adjWidth The box-adjusted width that was set
15873      * @param {Number} adjHeight The box-adjusted height that was set
15874      * @param {Number} rawWidth The width that was originally specified
15875      * @param {Number} rawHeight The height that was originally specified
15876      */
15877     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15878
15879     },
15880
15881     /**
15882      * Called after the component is moved, this method is empty by default but can be implemented by any
15883      * subclass that needs to perform custom logic after a move occurs.
15884      * @param {Number} x The new x position
15885      * @param {Number} y The new y position
15886      */
15887     onPosition : function(x, y){
15888
15889     },
15890
15891     // private
15892     adjustSize : function(w, h){
15893         if(this.autoWidth){
15894             w = 'auto';
15895         }
15896         if(this.autoHeight){
15897             h = 'auto';
15898         }
15899         return {width : w, height: h};
15900     },
15901
15902     // private
15903     adjustPosition : function(x, y){
15904         return {x : x, y: y};
15905     }
15906 });/*
15907  * Original code for Roojs - LGPL
15908  * <script type="text/javascript">
15909  */
15910  
15911 /**
15912  * @class Roo.XComponent
15913  * A delayed Element creator...
15914  * Or a way to group chunks of interface together.
15915  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15916  *  used in conjunction with XComponent.build() it will create an instance of each element,
15917  *  then call addxtype() to build the User interface.
15918  * 
15919  * Mypart.xyx = new Roo.XComponent({
15920
15921     parent : 'Mypart.xyz', // empty == document.element.!!
15922     order : '001',
15923     name : 'xxxx'
15924     region : 'xxxx'
15925     disabled : function() {} 
15926      
15927     tree : function() { // return an tree of xtype declared components
15928         var MODULE = this;
15929         return 
15930         {
15931             xtype : 'NestedLayoutPanel',
15932             // technicall
15933         }
15934      ]
15935  *})
15936  *
15937  *
15938  * It can be used to build a big heiracy, with parent etc.
15939  * or you can just use this to render a single compoent to a dom element
15940  * MYPART.render(Roo.Element | String(id) | dom_element )
15941  *
15942  *
15943  * Usage patterns.
15944  *
15945  * Classic Roo
15946  *
15947  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15948  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15949  *
15950  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15951  *
15952  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15953  * - if mulitple topModules exist, the last one is defined as the top module.
15954  *
15955  * Embeded Roo
15956  * 
15957  * When the top level or multiple modules are to embedded into a existing HTML page,
15958  * the parent element can container '#id' of the element where the module will be drawn.
15959  *
15960  * Bootstrap Roo
15961  *
15962  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15963  * it relies more on a include mechanism, where sub modules are included into an outer page.
15964  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15965  * 
15966  * Bootstrap Roo Included elements
15967  *
15968  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15969  * hence confusing the component builder as it thinks there are multiple top level elements. 
15970  *
15971  * 
15972  * 
15973  * @extends Roo.util.Observable
15974  * @constructor
15975  * @param cfg {Object} configuration of component
15976  * 
15977  */
15978 Roo.XComponent = function(cfg) {
15979     Roo.apply(this, cfg);
15980     this.addEvents({ 
15981         /**
15982              * @event built
15983              * Fires when this the componnt is built
15984              * @param {Roo.XComponent} c the component
15985              */
15986         'built' : true
15987         
15988     });
15989     this.region = this.region || 'center'; // default..
15990     Roo.XComponent.register(this);
15991     this.modules = false;
15992     this.el = false; // where the layout goes..
15993     
15994     
15995 }
15996 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15997     /**
15998      * @property el
15999      * The created element (with Roo.factory())
16000      * @type {Roo.Layout}
16001      */
16002     el  : false,
16003     
16004     /**
16005      * @property el
16006      * for BC  - use el in new code
16007      * @type {Roo.Layout}
16008      */
16009     panel : false,
16010     
16011     /**
16012      * @property layout
16013      * for BC  - use el in new code
16014      * @type {Roo.Layout}
16015      */
16016     layout : false,
16017     
16018      /**
16019      * @cfg {Function|boolean} disabled
16020      * If this module is disabled by some rule, return true from the funtion
16021      */
16022     disabled : false,
16023     
16024     /**
16025      * @cfg {String} parent 
16026      * Name of parent element which it get xtype added to..
16027      */
16028     parent: false,
16029     
16030     /**
16031      * @cfg {String} order
16032      * Used to set the order in which elements are created (usefull for multiple tabs)
16033      */
16034     
16035     order : false,
16036     /**
16037      * @cfg {String} name
16038      * String to display while loading.
16039      */
16040     name : false,
16041     /**
16042      * @cfg {String} region
16043      * Region to render component to (defaults to center)
16044      */
16045     region : 'center',
16046     
16047     /**
16048      * @cfg {Array} items
16049      * A single item array - the first element is the root of the tree..
16050      * It's done this way to stay compatible with the Xtype system...
16051      */
16052     items : false,
16053     
16054     /**
16055      * @property _tree
16056      * The method that retuns the tree of parts that make up this compoennt 
16057      * @type {function}
16058      */
16059     _tree  : false,
16060     
16061      /**
16062      * render
16063      * render element to dom or tree
16064      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16065      */
16066     
16067     render : function(el)
16068     {
16069         
16070         el = el || false;
16071         var hp = this.parent ? 1 : 0;
16072         Roo.debug &&  Roo.log(this);
16073         
16074         var tree = this._tree ? this._tree() : this.tree();
16075
16076         
16077         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16078             // if parent is a '#.....' string, then let's use that..
16079             var ename = this.parent.substr(1);
16080             this.parent = false;
16081             Roo.debug && Roo.log(ename);
16082             switch (ename) {
16083                 case 'bootstrap-body':
16084                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16085                         // this is the BorderLayout standard?
16086                        this.parent = { el : true };
16087                        break;
16088                     }
16089                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16090                         // need to insert stuff...
16091                         this.parent =  {
16092                              el : new Roo.bootstrap.layout.Border({
16093                                  el : document.body, 
16094                      
16095                                  center: {
16096                                     titlebar: false,
16097                                     autoScroll:false,
16098                                     closeOnTab: true,
16099                                     tabPosition: 'top',
16100                                       //resizeTabs: true,
16101                                     alwaysShowTabs: true,
16102                                     hideTabs: false
16103                                      //minTabWidth: 140
16104                                  }
16105                              })
16106                         
16107                          };
16108                          break;
16109                     }
16110                          
16111                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16112                         this.parent = { el :  new  Roo.bootstrap.Body() };
16113                         Roo.debug && Roo.log("setting el to doc body");
16114                          
16115                     } else {
16116                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16117                     }
16118                     break;
16119                 case 'bootstrap':
16120                     this.parent = { el : true};
16121                     // fall through
16122                 default:
16123                     el = Roo.get(ename);
16124                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16125                         this.parent = { el : true};
16126                     }
16127                     
16128                     break;
16129             }
16130                 
16131             
16132             if (!el && !this.parent) {
16133                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16134                 return;
16135             }
16136         }
16137         
16138         Roo.debug && Roo.log("EL:");
16139         Roo.debug && Roo.log(el);
16140         Roo.debug && Roo.log("this.parent.el:");
16141         Roo.debug && Roo.log(this.parent.el);
16142         
16143
16144         // altertive root elements ??? - we need a better way to indicate these.
16145         var is_alt = Roo.XComponent.is_alt ||
16146                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16147                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16148                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16149         
16150         
16151         
16152         if (!this.parent && is_alt) {
16153             //el = Roo.get(document.body);
16154             this.parent = { el : true };
16155         }
16156             
16157             
16158         
16159         if (!this.parent) {
16160             
16161             Roo.debug && Roo.log("no parent - creating one");
16162             
16163             el = el ? Roo.get(el) : false;      
16164             
16165             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16166                 
16167                 this.parent =  {
16168                     el : new Roo.bootstrap.layout.Border({
16169                         el: el || document.body,
16170                     
16171                         center: {
16172                             titlebar: false,
16173                             autoScroll:false,
16174                             closeOnTab: true,
16175                             tabPosition: 'top',
16176                              //resizeTabs: true,
16177                             alwaysShowTabs: false,
16178                             hideTabs: true,
16179                             minTabWidth: 140,
16180                             overflow: 'visible'
16181                          }
16182                      })
16183                 };
16184             } else {
16185             
16186                 // it's a top level one..
16187                 this.parent =  {
16188                     el : new Roo.BorderLayout(el || document.body, {
16189                         center: {
16190                             titlebar: false,
16191                             autoScroll:false,
16192                             closeOnTab: true,
16193                             tabPosition: 'top',
16194                              //resizeTabs: true,
16195                             alwaysShowTabs: el && hp? false :  true,
16196                             hideTabs: el || !hp ? true :  false,
16197                             minTabWidth: 140
16198                          }
16199                     })
16200                 };
16201             }
16202         }
16203         
16204         if (!this.parent.el) {
16205                 // probably an old style ctor, which has been disabled.
16206                 return;
16207
16208         }
16209                 // The 'tree' method is  '_tree now' 
16210             
16211         tree.region = tree.region || this.region;
16212         var is_body = false;
16213         if (this.parent.el === true) {
16214             // bootstrap... - body..
16215             if (el) {
16216                 tree.el = el;
16217             }
16218             this.parent.el = Roo.factory(tree);
16219             is_body = true;
16220         }
16221         
16222         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16223         this.fireEvent('built', this);
16224         
16225         this.panel = this.el;
16226         this.layout = this.panel.layout;
16227         this.parentLayout = this.parent.layout  || false;  
16228          
16229     }
16230     
16231 });
16232
16233 Roo.apply(Roo.XComponent, {
16234     /**
16235      * @property  hideProgress
16236      * true to disable the building progress bar.. usefull on single page renders.
16237      * @type Boolean
16238      */
16239     hideProgress : false,
16240     /**
16241      * @property  buildCompleted
16242      * True when the builder has completed building the interface.
16243      * @type Boolean
16244      */
16245     buildCompleted : false,
16246      
16247     /**
16248      * @property  topModule
16249      * the upper most module - uses document.element as it's constructor.
16250      * @type Object
16251      */
16252      
16253     topModule  : false,
16254       
16255     /**
16256      * @property  modules
16257      * array of modules to be created by registration system.
16258      * @type {Array} of Roo.XComponent
16259      */
16260     
16261     modules : [],
16262     /**
16263      * @property  elmodules
16264      * array of modules to be created by which use #ID 
16265      * @type {Array} of Roo.XComponent
16266      */
16267      
16268     elmodules : [],
16269
16270      /**
16271      * @property  is_alt
16272      * Is an alternative Root - normally used by bootstrap or other systems,
16273      *    where the top element in the tree can wrap 'body' 
16274      * @type {boolean}  (default false)
16275      */
16276      
16277     is_alt : false,
16278     /**
16279      * @property  build_from_html
16280      * Build elements from html - used by bootstrap HTML stuff 
16281      *    - this is cleared after build is completed
16282      * @type {boolean}    (default false)
16283      */
16284      
16285     build_from_html : false,
16286     /**
16287      * Register components to be built later.
16288      *
16289      * This solves the following issues
16290      * - Building is not done on page load, but after an authentication process has occured.
16291      * - Interface elements are registered on page load
16292      * - Parent Interface elements may not be loaded before child, so this handles that..
16293      * 
16294      *
16295      * example:
16296      * 
16297      * MyApp.register({
16298           order : '000001',
16299           module : 'Pman.Tab.projectMgr',
16300           region : 'center',
16301           parent : 'Pman.layout',
16302           disabled : false,  // or use a function..
16303         })
16304      
16305      * * @param {Object} details about module
16306      */
16307     register : function(obj) {
16308                 
16309         Roo.XComponent.event.fireEvent('register', obj);
16310         switch(typeof(obj.disabled) ) {
16311                 
16312             case 'undefined':
16313                 break;
16314             
16315             case 'function':
16316                 if ( obj.disabled() ) {
16317                         return;
16318                 }
16319                 break;
16320             
16321             default:
16322                 if (obj.disabled) {
16323                         return;
16324                 }
16325                 break;
16326         }
16327                 
16328         this.modules.push(obj);
16329          
16330     },
16331     /**
16332      * convert a string to an object..
16333      * eg. 'AAA.BBB' -> finds AAA.BBB
16334
16335      */
16336     
16337     toObject : function(str)
16338     {
16339         if (!str || typeof(str) == 'object') {
16340             return str;
16341         }
16342         if (str.substring(0,1) == '#') {
16343             return str;
16344         }
16345
16346         var ar = str.split('.');
16347         var rt, o;
16348         rt = ar.shift();
16349             /** eval:var:o */
16350         try {
16351             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16352         } catch (e) {
16353             throw "Module not found : " + str;
16354         }
16355         
16356         if (o === false) {
16357             throw "Module not found : " + str;
16358         }
16359         Roo.each(ar, function(e) {
16360             if (typeof(o[e]) == 'undefined') {
16361                 throw "Module not found : " + str;
16362             }
16363             o = o[e];
16364         });
16365         
16366         return o;
16367         
16368     },
16369     
16370     
16371     /**
16372      * move modules into their correct place in the tree..
16373      * 
16374      */
16375     preBuild : function ()
16376     {
16377         var _t = this;
16378         Roo.each(this.modules , function (obj)
16379         {
16380             Roo.XComponent.event.fireEvent('beforebuild', obj);
16381             
16382             var opar = obj.parent;
16383             try { 
16384                 obj.parent = this.toObject(opar);
16385             } catch(e) {
16386                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16387                 return;
16388             }
16389             
16390             if (!obj.parent) {
16391                 Roo.debug && Roo.log("GOT top level module");
16392                 Roo.debug && Roo.log(obj);
16393                 obj.modules = new Roo.util.MixedCollection(false, 
16394                     function(o) { return o.order + '' }
16395                 );
16396                 this.topModule = obj;
16397                 return;
16398             }
16399                         // parent is a string (usually a dom element name..)
16400             if (typeof(obj.parent) == 'string') {
16401                 this.elmodules.push(obj);
16402                 return;
16403             }
16404             if (obj.parent.constructor != Roo.XComponent) {
16405                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16406             }
16407             if (!obj.parent.modules) {
16408                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16409                     function(o) { return o.order + '' }
16410                 );
16411             }
16412             if (obj.parent.disabled) {
16413                 obj.disabled = true;
16414             }
16415             obj.parent.modules.add(obj);
16416         }, this);
16417     },
16418     
16419      /**
16420      * make a list of modules to build.
16421      * @return {Array} list of modules. 
16422      */ 
16423     
16424     buildOrder : function()
16425     {
16426         var _this = this;
16427         var cmp = function(a,b) {   
16428             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16429         };
16430         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16431             throw "No top level modules to build";
16432         }
16433         
16434         // make a flat list in order of modules to build.
16435         var mods = this.topModule ? [ this.topModule ] : [];
16436                 
16437         
16438         // elmodules (is a list of DOM based modules )
16439         Roo.each(this.elmodules, function(e) {
16440             mods.push(e);
16441             if (!this.topModule &&
16442                 typeof(e.parent) == 'string' &&
16443                 e.parent.substring(0,1) == '#' &&
16444                 Roo.get(e.parent.substr(1))
16445                ) {
16446                 
16447                 _this.topModule = e;
16448             }
16449             
16450         });
16451
16452         
16453         // add modules to their parents..
16454         var addMod = function(m) {
16455             Roo.debug && Roo.log("build Order: add: " + m.name);
16456                 
16457             mods.push(m);
16458             if (m.modules && !m.disabled) {
16459                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16460                 m.modules.keySort('ASC',  cmp );
16461                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16462     
16463                 m.modules.each(addMod);
16464             } else {
16465                 Roo.debug && Roo.log("build Order: no child modules");
16466             }
16467             // not sure if this is used any more..
16468             if (m.finalize) {
16469                 m.finalize.name = m.name + " (clean up) ";
16470                 mods.push(m.finalize);
16471             }
16472             
16473         }
16474         if (this.topModule && this.topModule.modules) { 
16475             this.topModule.modules.keySort('ASC',  cmp );
16476             this.topModule.modules.each(addMod);
16477         } 
16478         return mods;
16479     },
16480     
16481      /**
16482      * Build the registered modules.
16483      * @param {Object} parent element.
16484      * @param {Function} optional method to call after module has been added.
16485      * 
16486      */ 
16487    
16488     build : function(opts) 
16489     {
16490         
16491         if (typeof(opts) != 'undefined') {
16492             Roo.apply(this,opts);
16493         }
16494         
16495         this.preBuild();
16496         var mods = this.buildOrder();
16497       
16498         //this.allmods = mods;
16499         //Roo.debug && Roo.log(mods);
16500         //return;
16501         if (!mods.length) { // should not happen
16502             throw "NO modules!!!";
16503         }
16504         
16505         
16506         var msg = "Building Interface...";
16507         // flash it up as modal - so we store the mask!?
16508         if (!this.hideProgress && Roo.MessageBox) {
16509             Roo.MessageBox.show({ title: 'loading' });
16510             Roo.MessageBox.show({
16511                title: "Please wait...",
16512                msg: msg,
16513                width:450,
16514                progress:true,
16515                closable:false,
16516                modal: false
16517               
16518             });
16519         }
16520         var total = mods.length;
16521         
16522         var _this = this;
16523         var progressRun = function() {
16524             if (!mods.length) {
16525                 Roo.debug && Roo.log('hide?');
16526                 if (!this.hideProgress && Roo.MessageBox) {
16527                     Roo.MessageBox.hide();
16528                 }
16529                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16530                 
16531                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16532                 
16533                 // THE END...
16534                 return false;   
16535             }
16536             
16537             var m = mods.shift();
16538             
16539             
16540             Roo.debug && Roo.log(m);
16541             // not sure if this is supported any more.. - modules that are are just function
16542             if (typeof(m) == 'function') { 
16543                 m.call(this);
16544                 return progressRun.defer(10, _this);
16545             } 
16546             
16547             
16548             msg = "Building Interface " + (total  - mods.length) + 
16549                     " of " + total + 
16550                     (m.name ? (' - ' + m.name) : '');
16551                         Roo.debug && Roo.log(msg);
16552             if (!_this.hideProgress &&  Roo.MessageBox) { 
16553                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16554             }
16555             
16556          
16557             // is the module disabled?
16558             var disabled = (typeof(m.disabled) == 'function') ?
16559                 m.disabled.call(m.module.disabled) : m.disabled;    
16560             
16561             
16562             if (disabled) {
16563                 return progressRun(); // we do not update the display!
16564             }
16565             
16566             // now build 
16567             
16568                         
16569                         
16570             m.render();
16571             // it's 10 on top level, and 1 on others??? why...
16572             return progressRun.defer(10, _this);
16573              
16574         }
16575         progressRun.defer(1, _this);
16576      
16577         
16578         
16579     },
16580         
16581         
16582         /**
16583          * Event Object.
16584          *
16585          *
16586          */
16587         event: false, 
16588     /**
16589          * wrapper for event.on - aliased later..  
16590          * Typically use to register a event handler for register:
16591          *
16592          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16593          *
16594          */
16595     on : false
16596    
16597     
16598     
16599 });
16600
16601 Roo.XComponent.event = new Roo.util.Observable({
16602                 events : { 
16603                         /**
16604                          * @event register
16605                          * Fires when an Component is registered,
16606                          * set the disable property on the Component to stop registration.
16607                          * @param {Roo.XComponent} c the component being registerd.
16608                          * 
16609                          */
16610                         'register' : true,
16611             /**
16612                          * @event beforebuild
16613                          * Fires before each Component is built
16614                          * can be used to apply permissions.
16615                          * @param {Roo.XComponent} c the component being registerd.
16616                          * 
16617                          */
16618                         'beforebuild' : true,
16619                         /**
16620                          * @event buildcomplete
16621                          * Fires on the top level element when all elements have been built
16622                          * @param {Roo.XComponent} the top level component.
16623                          */
16624                         'buildcomplete' : true
16625                         
16626                 }
16627 });
16628
16629 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16630  //
16631  /**
16632  * marked - a markdown parser
16633  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16634  * https://github.com/chjj/marked
16635  */
16636
16637
16638 /**
16639  *
16640  * Roo.Markdown - is a very crude wrapper around marked..
16641  *
16642  * usage:
16643  * 
16644  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16645  * 
16646  * Note: move the sample code to the bottom of this
16647  * file before uncommenting it.
16648  *
16649  */
16650
16651 Roo.Markdown = {};
16652 Roo.Markdown.toHtml = function(text) {
16653     
16654     var c = new Roo.Markdown.marked.setOptions({
16655             renderer: new Roo.Markdown.marked.Renderer(),
16656             gfm: true,
16657             tables: true,
16658             breaks: false,
16659             pedantic: false,
16660             sanitize: false,
16661             smartLists: true,
16662             smartypants: false
16663           });
16664     // A FEW HACKS!!?
16665     
16666     text = text.replace(/\\\n/g,' ');
16667     return Roo.Markdown.marked(text);
16668 };
16669 //
16670 // converter
16671 //
16672 // Wraps all "globals" so that the only thing
16673 // exposed is makeHtml().
16674 //
16675 (function() {
16676     
16677     /**
16678      * Block-Level Grammar
16679      */
16680     
16681     var block = {
16682       newline: /^\n+/,
16683       code: /^( {4}[^\n]+\n*)+/,
16684       fences: noop,
16685       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16686       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16687       nptable: noop,
16688       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16689       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16690       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16691       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16692       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16693       table: noop,
16694       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16695       text: /^[^\n]+/
16696     };
16697     
16698     block.bullet = /(?:[*+-]|\d+\.)/;
16699     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16700     block.item = replace(block.item, 'gm')
16701       (/bull/g, block.bullet)
16702       ();
16703     
16704     block.list = replace(block.list)
16705       (/bull/g, block.bullet)
16706       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16707       ('def', '\\n+(?=' + block.def.source + ')')
16708       ();
16709     
16710     block.blockquote = replace(block.blockquote)
16711       ('def', block.def)
16712       ();
16713     
16714     block._tag = '(?!(?:'
16715       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16716       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16717       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16718     
16719     block.html = replace(block.html)
16720       ('comment', /<!--[\s\S]*?-->/)
16721       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16722       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16723       (/tag/g, block._tag)
16724       ();
16725     
16726     block.paragraph = replace(block.paragraph)
16727       ('hr', block.hr)
16728       ('heading', block.heading)
16729       ('lheading', block.lheading)
16730       ('blockquote', block.blockquote)
16731       ('tag', '<' + block._tag)
16732       ('def', block.def)
16733       ();
16734     
16735     /**
16736      * Normal Block Grammar
16737      */
16738     
16739     block.normal = merge({}, block);
16740     
16741     /**
16742      * GFM Block Grammar
16743      */
16744     
16745     block.gfm = merge({}, block.normal, {
16746       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16747       paragraph: /^/,
16748       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16749     });
16750     
16751     block.gfm.paragraph = replace(block.paragraph)
16752       ('(?!', '(?!'
16753         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16754         + block.list.source.replace('\\1', '\\3') + '|')
16755       ();
16756     
16757     /**
16758      * GFM + Tables Block Grammar
16759      */
16760     
16761     block.tables = merge({}, block.gfm, {
16762       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16763       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16764     });
16765     
16766     /**
16767      * Block Lexer
16768      */
16769     
16770     function Lexer(options) {
16771       this.tokens = [];
16772       this.tokens.links = {};
16773       this.options = options || marked.defaults;
16774       this.rules = block.normal;
16775     
16776       if (this.options.gfm) {
16777         if (this.options.tables) {
16778           this.rules = block.tables;
16779         } else {
16780           this.rules = block.gfm;
16781         }
16782       }
16783     }
16784     
16785     /**
16786      * Expose Block Rules
16787      */
16788     
16789     Lexer.rules = block;
16790     
16791     /**
16792      * Static Lex Method
16793      */
16794     
16795     Lexer.lex = function(src, options) {
16796       var lexer = new Lexer(options);
16797       return lexer.lex(src);
16798     };
16799     
16800     /**
16801      * Preprocessing
16802      */
16803     
16804     Lexer.prototype.lex = function(src) {
16805       src = src
16806         .replace(/\r\n|\r/g, '\n')
16807         .replace(/\t/g, '    ')
16808         .replace(/\u00a0/g, ' ')
16809         .replace(/\u2424/g, '\n');
16810     
16811       return this.token(src, true);
16812     };
16813     
16814     /**
16815      * Lexing
16816      */
16817     
16818     Lexer.prototype.token = function(src, top, bq) {
16819       var src = src.replace(/^ +$/gm, '')
16820         , next
16821         , loose
16822         , cap
16823         , bull
16824         , b
16825         , item
16826         , space
16827         , i
16828         , l;
16829     
16830       while (src) {
16831         // newline
16832         if (cap = this.rules.newline.exec(src)) {
16833           src = src.substring(cap[0].length);
16834           if (cap[0].length > 1) {
16835             this.tokens.push({
16836               type: 'space'
16837             });
16838           }
16839         }
16840     
16841         // code
16842         if (cap = this.rules.code.exec(src)) {
16843           src = src.substring(cap[0].length);
16844           cap = cap[0].replace(/^ {4}/gm, '');
16845           this.tokens.push({
16846             type: 'code',
16847             text: !this.options.pedantic
16848               ? cap.replace(/\n+$/, '')
16849               : cap
16850           });
16851           continue;
16852         }
16853     
16854         // fences (gfm)
16855         if (cap = this.rules.fences.exec(src)) {
16856           src = src.substring(cap[0].length);
16857           this.tokens.push({
16858             type: 'code',
16859             lang: cap[2],
16860             text: cap[3] || ''
16861           });
16862           continue;
16863         }
16864     
16865         // heading
16866         if (cap = this.rules.heading.exec(src)) {
16867           src = src.substring(cap[0].length);
16868           this.tokens.push({
16869             type: 'heading',
16870             depth: cap[1].length,
16871             text: cap[2]
16872           });
16873           continue;
16874         }
16875     
16876         // table no leading pipe (gfm)
16877         if (top && (cap = this.rules.nptable.exec(src))) {
16878           src = src.substring(cap[0].length);
16879     
16880           item = {
16881             type: 'table',
16882             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16883             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16884             cells: cap[3].replace(/\n$/, '').split('\n')
16885           };
16886     
16887           for (i = 0; i < item.align.length; i++) {
16888             if (/^ *-+: *$/.test(item.align[i])) {
16889               item.align[i] = 'right';
16890             } else if (/^ *:-+: *$/.test(item.align[i])) {
16891               item.align[i] = 'center';
16892             } else if (/^ *:-+ *$/.test(item.align[i])) {
16893               item.align[i] = 'left';
16894             } else {
16895               item.align[i] = null;
16896             }
16897           }
16898     
16899           for (i = 0; i < item.cells.length; i++) {
16900             item.cells[i] = item.cells[i].split(/ *\| */);
16901           }
16902     
16903           this.tokens.push(item);
16904     
16905           continue;
16906         }
16907     
16908         // lheading
16909         if (cap = this.rules.lheading.exec(src)) {
16910           src = src.substring(cap[0].length);
16911           this.tokens.push({
16912             type: 'heading',
16913             depth: cap[2] === '=' ? 1 : 2,
16914             text: cap[1]
16915           });
16916           continue;
16917         }
16918     
16919         // hr
16920         if (cap = this.rules.hr.exec(src)) {
16921           src = src.substring(cap[0].length);
16922           this.tokens.push({
16923             type: 'hr'
16924           });
16925           continue;
16926         }
16927     
16928         // blockquote
16929         if (cap = this.rules.blockquote.exec(src)) {
16930           src = src.substring(cap[0].length);
16931     
16932           this.tokens.push({
16933             type: 'blockquote_start'
16934           });
16935     
16936           cap = cap[0].replace(/^ *> ?/gm, '');
16937     
16938           // Pass `top` to keep the current
16939           // "toplevel" state. This is exactly
16940           // how markdown.pl works.
16941           this.token(cap, top, true);
16942     
16943           this.tokens.push({
16944             type: 'blockquote_end'
16945           });
16946     
16947           continue;
16948         }
16949     
16950         // list
16951         if (cap = this.rules.list.exec(src)) {
16952           src = src.substring(cap[0].length);
16953           bull = cap[2];
16954     
16955           this.tokens.push({
16956             type: 'list_start',
16957             ordered: bull.length > 1
16958           });
16959     
16960           // Get each top-level item.
16961           cap = cap[0].match(this.rules.item);
16962     
16963           next = false;
16964           l = cap.length;
16965           i = 0;
16966     
16967           for (; i < l; i++) {
16968             item = cap[i];
16969     
16970             // Remove the list item's bullet
16971             // so it is seen as the next token.
16972             space = item.length;
16973             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16974     
16975             // Outdent whatever the
16976             // list item contains. Hacky.
16977             if (~item.indexOf('\n ')) {
16978               space -= item.length;
16979               item = !this.options.pedantic
16980                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16981                 : item.replace(/^ {1,4}/gm, '');
16982             }
16983     
16984             // Determine whether the next list item belongs here.
16985             // Backpedal if it does not belong in this list.
16986             if (this.options.smartLists && i !== l - 1) {
16987               b = block.bullet.exec(cap[i + 1])[0];
16988               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16989                 src = cap.slice(i + 1).join('\n') + src;
16990                 i = l - 1;
16991               }
16992             }
16993     
16994             // Determine whether item is loose or not.
16995             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16996             // for discount behavior.
16997             loose = next || /\n\n(?!\s*$)/.test(item);
16998             if (i !== l - 1) {
16999               next = item.charAt(item.length - 1) === '\n';
17000               if (!loose) { loose = next; }
17001             }
17002     
17003             this.tokens.push({
17004               type: loose
17005                 ? 'loose_item_start'
17006                 : 'list_item_start'
17007             });
17008     
17009             // Recurse.
17010             this.token(item, false, bq);
17011     
17012             this.tokens.push({
17013               type: 'list_item_end'
17014             });
17015           }
17016     
17017           this.tokens.push({
17018             type: 'list_end'
17019           });
17020     
17021           continue;
17022         }
17023     
17024         // html
17025         if (cap = this.rules.html.exec(src)) {
17026           src = src.substring(cap[0].length);
17027           this.tokens.push({
17028             type: this.options.sanitize
17029               ? 'paragraph'
17030               : 'html',
17031             pre: !this.options.sanitizer
17032               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17033             text: cap[0]
17034           });
17035           continue;
17036         }
17037     
17038         // def
17039         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17040           src = src.substring(cap[0].length);
17041           this.tokens.links[cap[1].toLowerCase()] = {
17042             href: cap[2],
17043             title: cap[3]
17044           };
17045           continue;
17046         }
17047     
17048         // table (gfm)
17049         if (top && (cap = this.rules.table.exec(src))) {
17050           src = src.substring(cap[0].length);
17051     
17052           item = {
17053             type: 'table',
17054             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17055             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17056             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17057           };
17058     
17059           for (i = 0; i < item.align.length; i++) {
17060             if (/^ *-+: *$/.test(item.align[i])) {
17061               item.align[i] = 'right';
17062             } else if (/^ *:-+: *$/.test(item.align[i])) {
17063               item.align[i] = 'center';
17064             } else if (/^ *:-+ *$/.test(item.align[i])) {
17065               item.align[i] = 'left';
17066             } else {
17067               item.align[i] = null;
17068             }
17069           }
17070     
17071           for (i = 0; i < item.cells.length; i++) {
17072             item.cells[i] = item.cells[i]
17073               .replace(/^ *\| *| *\| *$/g, '')
17074               .split(/ *\| */);
17075           }
17076     
17077           this.tokens.push(item);
17078     
17079           continue;
17080         }
17081     
17082         // top-level paragraph
17083         if (top && (cap = this.rules.paragraph.exec(src))) {
17084           src = src.substring(cap[0].length);
17085           this.tokens.push({
17086             type: 'paragraph',
17087             text: cap[1].charAt(cap[1].length - 1) === '\n'
17088               ? cap[1].slice(0, -1)
17089               : cap[1]
17090           });
17091           continue;
17092         }
17093     
17094         // text
17095         if (cap = this.rules.text.exec(src)) {
17096           // Top-level should never reach here.
17097           src = src.substring(cap[0].length);
17098           this.tokens.push({
17099             type: 'text',
17100             text: cap[0]
17101           });
17102           continue;
17103         }
17104     
17105         if (src) {
17106           throw new
17107             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17108         }
17109       }
17110     
17111       return this.tokens;
17112     };
17113     
17114     /**
17115      * Inline-Level Grammar
17116      */
17117     
17118     var inline = {
17119       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17120       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17121       url: noop,
17122       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17123       link: /^!?\[(inside)\]\(href\)/,
17124       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17125       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17126       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17127       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17128       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17129       br: /^ {2,}\n(?!\s*$)/,
17130       del: noop,
17131       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17132     };
17133     
17134     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17135     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17136     
17137     inline.link = replace(inline.link)
17138       ('inside', inline._inside)
17139       ('href', inline._href)
17140       ();
17141     
17142     inline.reflink = replace(inline.reflink)
17143       ('inside', inline._inside)
17144       ();
17145     
17146     /**
17147      * Normal Inline Grammar
17148      */
17149     
17150     inline.normal = merge({}, inline);
17151     
17152     /**
17153      * Pedantic Inline Grammar
17154      */
17155     
17156     inline.pedantic = merge({}, inline.normal, {
17157       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17158       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17159     });
17160     
17161     /**
17162      * GFM Inline Grammar
17163      */
17164     
17165     inline.gfm = merge({}, inline.normal, {
17166       escape: replace(inline.escape)('])', '~|])')(),
17167       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17168       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17169       text: replace(inline.text)
17170         (']|', '~]|')
17171         ('|', '|https?://|')
17172         ()
17173     });
17174     
17175     /**
17176      * GFM + Line Breaks Inline Grammar
17177      */
17178     
17179     inline.breaks = merge({}, inline.gfm, {
17180       br: replace(inline.br)('{2,}', '*')(),
17181       text: replace(inline.gfm.text)('{2,}', '*')()
17182     });
17183     
17184     /**
17185      * Inline Lexer & Compiler
17186      */
17187     
17188     function InlineLexer(links, options) {
17189       this.options = options || marked.defaults;
17190       this.links = links;
17191       this.rules = inline.normal;
17192       this.renderer = this.options.renderer || new Renderer;
17193       this.renderer.options = this.options;
17194     
17195       if (!this.links) {
17196         throw new
17197           Error('Tokens array requires a `links` property.');
17198       }
17199     
17200       if (this.options.gfm) {
17201         if (this.options.breaks) {
17202           this.rules = inline.breaks;
17203         } else {
17204           this.rules = inline.gfm;
17205         }
17206       } else if (this.options.pedantic) {
17207         this.rules = inline.pedantic;
17208       }
17209     }
17210     
17211     /**
17212      * Expose Inline Rules
17213      */
17214     
17215     InlineLexer.rules = inline;
17216     
17217     /**
17218      * Static Lexing/Compiling Method
17219      */
17220     
17221     InlineLexer.output = function(src, links, options) {
17222       var inline = new InlineLexer(links, options);
17223       return inline.output(src);
17224     };
17225     
17226     /**
17227      * Lexing/Compiling
17228      */
17229     
17230     InlineLexer.prototype.output = function(src) {
17231       var out = ''
17232         , link
17233         , text
17234         , href
17235         , cap;
17236     
17237       while (src) {
17238         // escape
17239         if (cap = this.rules.escape.exec(src)) {
17240           src = src.substring(cap[0].length);
17241           out += cap[1];
17242           continue;
17243         }
17244     
17245         // autolink
17246         if (cap = this.rules.autolink.exec(src)) {
17247           src = src.substring(cap[0].length);
17248           if (cap[2] === '@') {
17249             text = cap[1].charAt(6) === ':'
17250               ? this.mangle(cap[1].substring(7))
17251               : this.mangle(cap[1]);
17252             href = this.mangle('mailto:') + text;
17253           } else {
17254             text = escape(cap[1]);
17255             href = text;
17256           }
17257           out += this.renderer.link(href, null, text);
17258           continue;
17259         }
17260     
17261         // url (gfm)
17262         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17263           src = src.substring(cap[0].length);
17264           text = escape(cap[1]);
17265           href = text;
17266           out += this.renderer.link(href, null, text);
17267           continue;
17268         }
17269     
17270         // tag
17271         if (cap = this.rules.tag.exec(src)) {
17272           if (!this.inLink && /^<a /i.test(cap[0])) {
17273             this.inLink = true;
17274           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17275             this.inLink = false;
17276           }
17277           src = src.substring(cap[0].length);
17278           out += this.options.sanitize
17279             ? this.options.sanitizer
17280               ? this.options.sanitizer(cap[0])
17281               : escape(cap[0])
17282             : cap[0];
17283           continue;
17284         }
17285     
17286         // link
17287         if (cap = this.rules.link.exec(src)) {
17288           src = src.substring(cap[0].length);
17289           this.inLink = true;
17290           out += this.outputLink(cap, {
17291             href: cap[2],
17292             title: cap[3]
17293           });
17294           this.inLink = false;
17295           continue;
17296         }
17297     
17298         // reflink, nolink
17299         if ((cap = this.rules.reflink.exec(src))
17300             || (cap = this.rules.nolink.exec(src))) {
17301           src = src.substring(cap[0].length);
17302           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17303           link = this.links[link.toLowerCase()];
17304           if (!link || !link.href) {
17305             out += cap[0].charAt(0);
17306             src = cap[0].substring(1) + src;
17307             continue;
17308           }
17309           this.inLink = true;
17310           out += this.outputLink(cap, link);
17311           this.inLink = false;
17312           continue;
17313         }
17314     
17315         // strong
17316         if (cap = this.rules.strong.exec(src)) {
17317           src = src.substring(cap[0].length);
17318           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17319           continue;
17320         }
17321     
17322         // em
17323         if (cap = this.rules.em.exec(src)) {
17324           src = src.substring(cap[0].length);
17325           out += this.renderer.em(this.output(cap[2] || cap[1]));
17326           continue;
17327         }
17328     
17329         // code
17330         if (cap = this.rules.code.exec(src)) {
17331           src = src.substring(cap[0].length);
17332           out += this.renderer.codespan(escape(cap[2], true));
17333           continue;
17334         }
17335     
17336         // br
17337         if (cap = this.rules.br.exec(src)) {
17338           src = src.substring(cap[0].length);
17339           out += this.renderer.br();
17340           continue;
17341         }
17342     
17343         // del (gfm)
17344         if (cap = this.rules.del.exec(src)) {
17345           src = src.substring(cap[0].length);
17346           out += this.renderer.del(this.output(cap[1]));
17347           continue;
17348         }
17349     
17350         // text
17351         if (cap = this.rules.text.exec(src)) {
17352           src = src.substring(cap[0].length);
17353           out += this.renderer.text(escape(this.smartypants(cap[0])));
17354           continue;
17355         }
17356     
17357         if (src) {
17358           throw new
17359             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17360         }
17361       }
17362     
17363       return out;
17364     };
17365     
17366     /**
17367      * Compile Link
17368      */
17369     
17370     InlineLexer.prototype.outputLink = function(cap, link) {
17371       var href = escape(link.href)
17372         , title = link.title ? escape(link.title) : null;
17373     
17374       return cap[0].charAt(0) !== '!'
17375         ? this.renderer.link(href, title, this.output(cap[1]))
17376         : this.renderer.image(href, title, escape(cap[1]));
17377     };
17378     
17379     /**
17380      * Smartypants Transformations
17381      */
17382     
17383     InlineLexer.prototype.smartypants = function(text) {
17384       if (!this.options.smartypants)  { return text; }
17385       return text
17386         // em-dashes
17387         .replace(/---/g, '\u2014')
17388         // en-dashes
17389         .replace(/--/g, '\u2013')
17390         // opening singles
17391         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17392         // closing singles & apostrophes
17393         .replace(/'/g, '\u2019')
17394         // opening doubles
17395         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17396         // closing doubles
17397         .replace(/"/g, '\u201d')
17398         // ellipses
17399         .replace(/\.{3}/g, '\u2026');
17400     };
17401     
17402     /**
17403      * Mangle Links
17404      */
17405     
17406     InlineLexer.prototype.mangle = function(text) {
17407       if (!this.options.mangle) { return text; }
17408       var out = ''
17409         , l = text.length
17410         , i = 0
17411         , ch;
17412     
17413       for (; i < l; i++) {
17414         ch = text.charCodeAt(i);
17415         if (Math.random() > 0.5) {
17416           ch = 'x' + ch.toString(16);
17417         }
17418         out += '&#' + ch + ';';
17419       }
17420     
17421       return out;
17422     };
17423     
17424     /**
17425      * Renderer
17426      */
17427     
17428     function Renderer(options) {
17429       this.options = options || {};
17430     }
17431     
17432     Renderer.prototype.code = function(code, lang, escaped) {
17433       if (this.options.highlight) {
17434         var out = this.options.highlight(code, lang);
17435         if (out != null && out !== code) {
17436           escaped = true;
17437           code = out;
17438         }
17439       } else {
17440             // hack!!! - it's already escapeD?
17441             escaped = true;
17442       }
17443     
17444       if (!lang) {
17445         return '<pre><code>'
17446           + (escaped ? code : escape(code, true))
17447           + '\n</code></pre>';
17448       }
17449     
17450       return '<pre><code class="'
17451         + this.options.langPrefix
17452         + escape(lang, true)
17453         + '">'
17454         + (escaped ? code : escape(code, true))
17455         + '\n</code></pre>\n';
17456     };
17457     
17458     Renderer.prototype.blockquote = function(quote) {
17459       return '<blockquote>\n' + quote + '</blockquote>\n';
17460     };
17461     
17462     Renderer.prototype.html = function(html) {
17463       return html;
17464     };
17465     
17466     Renderer.prototype.heading = function(text, level, raw) {
17467       return '<h'
17468         + level
17469         + ' id="'
17470         + this.options.headerPrefix
17471         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17472         + '">'
17473         + text
17474         + '</h'
17475         + level
17476         + '>\n';
17477     };
17478     
17479     Renderer.prototype.hr = function() {
17480       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17481     };
17482     
17483     Renderer.prototype.list = function(body, ordered) {
17484       var type = ordered ? 'ol' : 'ul';
17485       return '<' + type + '>\n' + body + '</' + type + '>\n';
17486     };
17487     
17488     Renderer.prototype.listitem = function(text) {
17489       return '<li>' + text + '</li>\n';
17490     };
17491     
17492     Renderer.prototype.paragraph = function(text) {
17493       return '<p>' + text + '</p>\n';
17494     };
17495     
17496     Renderer.prototype.table = function(header, body) {
17497       return '<table class="table table-striped">\n'
17498         + '<thead>\n'
17499         + header
17500         + '</thead>\n'
17501         + '<tbody>\n'
17502         + body
17503         + '</tbody>\n'
17504         + '</table>\n';
17505     };
17506     
17507     Renderer.prototype.tablerow = function(content) {
17508       return '<tr>\n' + content + '</tr>\n';
17509     };
17510     
17511     Renderer.prototype.tablecell = function(content, flags) {
17512       var type = flags.header ? 'th' : 'td';
17513       var tag = flags.align
17514         ? '<' + type + ' style="text-align:' + flags.align + '">'
17515         : '<' + type + '>';
17516       return tag + content + '</' + type + '>\n';
17517     };
17518     
17519     // span level renderer
17520     Renderer.prototype.strong = function(text) {
17521       return '<strong>' + text + '</strong>';
17522     };
17523     
17524     Renderer.prototype.em = function(text) {
17525       return '<em>' + text + '</em>';
17526     };
17527     
17528     Renderer.prototype.codespan = function(text) {
17529       return '<code>' + text + '</code>';
17530     };
17531     
17532     Renderer.prototype.br = function() {
17533       return this.options.xhtml ? '<br/>' : '<br>';
17534     };
17535     
17536     Renderer.prototype.del = function(text) {
17537       return '<del>' + text + '</del>';
17538     };
17539     
17540     Renderer.prototype.link = function(href, title, text) {
17541       if (this.options.sanitize) {
17542         try {
17543           var prot = decodeURIComponent(unescape(href))
17544             .replace(/[^\w:]/g, '')
17545             .toLowerCase();
17546         } catch (e) {
17547           return '';
17548         }
17549         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17550           return '';
17551         }
17552       }
17553       var out = '<a href="' + href + '"';
17554       if (title) {
17555         out += ' title="' + title + '"';
17556       }
17557       out += '>' + text + '</a>';
17558       return out;
17559     };
17560     
17561     Renderer.prototype.image = function(href, title, text) {
17562       var out = '<img src="' + href + '" alt="' + text + '"';
17563       if (title) {
17564         out += ' title="' + title + '"';
17565       }
17566       out += this.options.xhtml ? '/>' : '>';
17567       return out;
17568     };
17569     
17570     Renderer.prototype.text = function(text) {
17571       return text;
17572     };
17573     
17574     /**
17575      * Parsing & Compiling
17576      */
17577     
17578     function Parser(options) {
17579       this.tokens = [];
17580       this.token = null;
17581       this.options = options || marked.defaults;
17582       this.options.renderer = this.options.renderer || new Renderer;
17583       this.renderer = this.options.renderer;
17584       this.renderer.options = this.options;
17585     }
17586     
17587     /**
17588      * Static Parse Method
17589      */
17590     
17591     Parser.parse = function(src, options, renderer) {
17592       var parser = new Parser(options, renderer);
17593       return parser.parse(src);
17594     };
17595     
17596     /**
17597      * Parse Loop
17598      */
17599     
17600     Parser.prototype.parse = function(src) {
17601       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17602       this.tokens = src.reverse();
17603     
17604       var out = '';
17605       while (this.next()) {
17606         out += this.tok();
17607       }
17608     
17609       return out;
17610     };
17611     
17612     /**
17613      * Next Token
17614      */
17615     
17616     Parser.prototype.next = function() {
17617       return this.token = this.tokens.pop();
17618     };
17619     
17620     /**
17621      * Preview Next Token
17622      */
17623     
17624     Parser.prototype.peek = function() {
17625       return this.tokens[this.tokens.length - 1] || 0;
17626     };
17627     
17628     /**
17629      * Parse Text Tokens
17630      */
17631     
17632     Parser.prototype.parseText = function() {
17633       var body = this.token.text;
17634     
17635       while (this.peek().type === 'text') {
17636         body += '\n' + this.next().text;
17637       }
17638     
17639       return this.inline.output(body);
17640     };
17641     
17642     /**
17643      * Parse Current Token
17644      */
17645     
17646     Parser.prototype.tok = function() {
17647       switch (this.token.type) {
17648         case 'space': {
17649           return '';
17650         }
17651         case 'hr': {
17652           return this.renderer.hr();
17653         }
17654         case 'heading': {
17655           return this.renderer.heading(
17656             this.inline.output(this.token.text),
17657             this.token.depth,
17658             this.token.text);
17659         }
17660         case 'code': {
17661           return this.renderer.code(this.token.text,
17662             this.token.lang,
17663             this.token.escaped);
17664         }
17665         case 'table': {
17666           var header = ''
17667             , body = ''
17668             , i
17669             , row
17670             , cell
17671             , flags
17672             , j;
17673     
17674           // header
17675           cell = '';
17676           for (i = 0; i < this.token.header.length; i++) {
17677             flags = { header: true, align: this.token.align[i] };
17678             cell += this.renderer.tablecell(
17679               this.inline.output(this.token.header[i]),
17680               { header: true, align: this.token.align[i] }
17681             );
17682           }
17683           header += this.renderer.tablerow(cell);
17684     
17685           for (i = 0; i < this.token.cells.length; i++) {
17686             row = this.token.cells[i];
17687     
17688             cell = '';
17689             for (j = 0; j < row.length; j++) {
17690               cell += this.renderer.tablecell(
17691                 this.inline.output(row[j]),
17692                 { header: false, align: this.token.align[j] }
17693               );
17694             }
17695     
17696             body += this.renderer.tablerow(cell);
17697           }
17698           return this.renderer.table(header, body);
17699         }
17700         case 'blockquote_start': {
17701           var body = '';
17702     
17703           while (this.next().type !== 'blockquote_end') {
17704             body += this.tok();
17705           }
17706     
17707           return this.renderer.blockquote(body);
17708         }
17709         case 'list_start': {
17710           var body = ''
17711             , ordered = this.token.ordered;
17712     
17713           while (this.next().type !== 'list_end') {
17714             body += this.tok();
17715           }
17716     
17717           return this.renderer.list(body, ordered);
17718         }
17719         case 'list_item_start': {
17720           var body = '';
17721     
17722           while (this.next().type !== 'list_item_end') {
17723             body += this.token.type === 'text'
17724               ? this.parseText()
17725               : this.tok();
17726           }
17727     
17728           return this.renderer.listitem(body);
17729         }
17730         case 'loose_item_start': {
17731           var body = '';
17732     
17733           while (this.next().type !== 'list_item_end') {
17734             body += this.tok();
17735           }
17736     
17737           return this.renderer.listitem(body);
17738         }
17739         case 'html': {
17740           var html = !this.token.pre && !this.options.pedantic
17741             ? this.inline.output(this.token.text)
17742             : this.token.text;
17743           return this.renderer.html(html);
17744         }
17745         case 'paragraph': {
17746           return this.renderer.paragraph(this.inline.output(this.token.text));
17747         }
17748         case 'text': {
17749           return this.renderer.paragraph(this.parseText());
17750         }
17751       }
17752     };
17753     
17754     /**
17755      * Helpers
17756      */
17757     
17758     function escape(html, encode) {
17759       return html
17760         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17761         .replace(/</g, '&lt;')
17762         .replace(/>/g, '&gt;')
17763         .replace(/"/g, '&quot;')
17764         .replace(/'/g, '&#39;');
17765     }
17766     
17767     function unescape(html) {
17768         // explicitly match decimal, hex, and named HTML entities 
17769       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17770         n = n.toLowerCase();
17771         if (n === 'colon') { return ':'; }
17772         if (n.charAt(0) === '#') {
17773           return n.charAt(1) === 'x'
17774             ? String.fromCharCode(parseInt(n.substring(2), 16))
17775             : String.fromCharCode(+n.substring(1));
17776         }
17777         return '';
17778       });
17779     }
17780     
17781     function replace(regex, opt) {
17782       regex = regex.source;
17783       opt = opt || '';
17784       return function self(name, val) {
17785         if (!name) { return new RegExp(regex, opt); }
17786         val = val.source || val;
17787         val = val.replace(/(^|[^\[])\^/g, '$1');
17788         regex = regex.replace(name, val);
17789         return self;
17790       };
17791     }
17792     
17793     function noop() {}
17794     noop.exec = noop;
17795     
17796     function merge(obj) {
17797       var i = 1
17798         , target
17799         , key;
17800     
17801       for (; i < arguments.length; i++) {
17802         target = arguments[i];
17803         for (key in target) {
17804           if (Object.prototype.hasOwnProperty.call(target, key)) {
17805             obj[key] = target[key];
17806           }
17807         }
17808       }
17809     
17810       return obj;
17811     }
17812     
17813     
17814     /**
17815      * Marked
17816      */
17817     
17818     function marked(src, opt, callback) {
17819       if (callback || typeof opt === 'function') {
17820         if (!callback) {
17821           callback = opt;
17822           opt = null;
17823         }
17824     
17825         opt = merge({}, marked.defaults, opt || {});
17826     
17827         var highlight = opt.highlight
17828           , tokens
17829           , pending
17830           , i = 0;
17831     
17832         try {
17833           tokens = Lexer.lex(src, opt)
17834         } catch (e) {
17835           return callback(e);
17836         }
17837     
17838         pending = tokens.length;
17839     
17840         var done = function(err) {
17841           if (err) {
17842             opt.highlight = highlight;
17843             return callback(err);
17844           }
17845     
17846           var out;
17847     
17848           try {
17849             out = Parser.parse(tokens, opt);
17850           } catch (e) {
17851             err = e;
17852           }
17853     
17854           opt.highlight = highlight;
17855     
17856           return err
17857             ? callback(err)
17858             : callback(null, out);
17859         };
17860     
17861         if (!highlight || highlight.length < 3) {
17862           return done();
17863         }
17864     
17865         delete opt.highlight;
17866     
17867         if (!pending) { return done(); }
17868     
17869         for (; i < tokens.length; i++) {
17870           (function(token) {
17871             if (token.type !== 'code') {
17872               return --pending || done();
17873             }
17874             return highlight(token.text, token.lang, function(err, code) {
17875               if (err) { return done(err); }
17876               if (code == null || code === token.text) {
17877                 return --pending || done();
17878               }
17879               token.text = code;
17880               token.escaped = true;
17881               --pending || done();
17882             });
17883           })(tokens[i]);
17884         }
17885     
17886         return;
17887       }
17888       try {
17889         if (opt) { opt = merge({}, marked.defaults, opt); }
17890         return Parser.parse(Lexer.lex(src, opt), opt);
17891       } catch (e) {
17892         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17893         if ((opt || marked.defaults).silent) {
17894           return '<p>An error occured:</p><pre>'
17895             + escape(e.message + '', true)
17896             + '</pre>';
17897         }
17898         throw e;
17899       }
17900     }
17901     
17902     /**
17903      * Options
17904      */
17905     
17906     marked.options =
17907     marked.setOptions = function(opt) {
17908       merge(marked.defaults, opt);
17909       return marked;
17910     };
17911     
17912     marked.defaults = {
17913       gfm: true,
17914       tables: true,
17915       breaks: false,
17916       pedantic: false,
17917       sanitize: false,
17918       sanitizer: null,
17919       mangle: true,
17920       smartLists: false,
17921       silent: false,
17922       highlight: null,
17923       langPrefix: 'lang-',
17924       smartypants: false,
17925       headerPrefix: '',
17926       renderer: new Renderer,
17927       xhtml: false
17928     };
17929     
17930     /**
17931      * Expose
17932      */
17933     
17934     marked.Parser = Parser;
17935     marked.parser = Parser.parse;
17936     
17937     marked.Renderer = Renderer;
17938     
17939     marked.Lexer = Lexer;
17940     marked.lexer = Lexer.lex;
17941     
17942     marked.InlineLexer = InlineLexer;
17943     marked.inlineLexer = InlineLexer.output;
17944     
17945     marked.parse = marked;
17946     
17947     Roo.Markdown.marked = marked;
17948
17949 })();/*
17950  * Based on:
17951  * Ext JS Library 1.1.1
17952  * Copyright(c) 2006-2007, Ext JS, LLC.
17953  *
17954  * Originally Released Under LGPL - original licence link has changed is not relivant.
17955  *
17956  * Fork - LGPL
17957  * <script type="text/javascript">
17958  */
17959
17960
17961
17962 /*
17963  * These classes are derivatives of the similarly named classes in the YUI Library.
17964  * The original license:
17965  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17966  * Code licensed under the BSD License:
17967  * http://developer.yahoo.net/yui/license.txt
17968  */
17969
17970 (function() {
17971
17972 var Event=Roo.EventManager;
17973 var Dom=Roo.lib.Dom;
17974
17975 /**
17976  * @class Roo.dd.DragDrop
17977  * @extends Roo.util.Observable
17978  * Defines the interface and base operation of items that that can be
17979  * dragged or can be drop targets.  It was designed to be extended, overriding
17980  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17981  * Up to three html elements can be associated with a DragDrop instance:
17982  * <ul>
17983  * <li>linked element: the element that is passed into the constructor.
17984  * This is the element which defines the boundaries for interaction with
17985  * other DragDrop objects.</li>
17986  * <li>handle element(s): The drag operation only occurs if the element that
17987  * was clicked matches a handle element.  By default this is the linked
17988  * element, but there are times that you will want only a portion of the
17989  * linked element to initiate the drag operation, and the setHandleElId()
17990  * method provides a way to define this.</li>
17991  * <li>drag element: this represents the element that would be moved along
17992  * with the cursor during a drag operation.  By default, this is the linked
17993  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17994  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17995  * </li>
17996  * </ul>
17997  * This class should not be instantiated until the onload event to ensure that
17998  * the associated elements are available.
17999  * The following would define a DragDrop obj that would interact with any
18000  * other DragDrop obj in the "group1" group:
18001  * <pre>
18002  *  dd = new Roo.dd.DragDrop("div1", "group1");
18003  * </pre>
18004  * Since none of the event handlers have been implemented, nothing would
18005  * actually happen if you were to run the code above.  Normally you would
18006  * override this class or one of the default implementations, but you can
18007  * also override the methods you want on an instance of the class...
18008  * <pre>
18009  *  dd.onDragDrop = function(e, id) {
18010  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18011  *  }
18012  * </pre>
18013  * @constructor
18014  * @param {String} id of the element that is linked to this instance
18015  * @param {String} sGroup the group of related DragDrop objects
18016  * @param {object} config an object containing configurable attributes
18017  *                Valid properties for DragDrop:
18018  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18019  */
18020 Roo.dd.DragDrop = function(id, sGroup, config) {
18021     if (id) {
18022         this.init(id, sGroup, config);
18023     }
18024     
18025 };
18026
18027 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18028
18029     /**
18030      * The id of the element associated with this object.  This is what we
18031      * refer to as the "linked element" because the size and position of
18032      * this element is used to determine when the drag and drop objects have
18033      * interacted.
18034      * @property id
18035      * @type String
18036      */
18037     id: null,
18038
18039     /**
18040      * Configuration attributes passed into the constructor
18041      * @property config
18042      * @type object
18043      */
18044     config: null,
18045
18046     /**
18047      * The id of the element that will be dragged.  By default this is same
18048      * as the linked element , but could be changed to another element. Ex:
18049      * Roo.dd.DDProxy
18050      * @property dragElId
18051      * @type String
18052      * @private
18053      */
18054     dragElId: null,
18055
18056     /**
18057      * the id of the element that initiates the drag operation.  By default
18058      * this is the linked element, but could be changed to be a child of this
18059      * element.  This lets us do things like only starting the drag when the
18060      * header element within the linked html element is clicked.
18061      * @property handleElId
18062      * @type String
18063      * @private
18064      */
18065     handleElId: null,
18066
18067     /**
18068      * An associative array of HTML tags that will be ignored if clicked.
18069      * @property invalidHandleTypes
18070      * @type {string: string}
18071      */
18072     invalidHandleTypes: null,
18073
18074     /**
18075      * An associative array of ids for elements that will be ignored if clicked
18076      * @property invalidHandleIds
18077      * @type {string: string}
18078      */
18079     invalidHandleIds: null,
18080
18081     /**
18082      * An indexted array of css class names for elements that will be ignored
18083      * if clicked.
18084      * @property invalidHandleClasses
18085      * @type string[]
18086      */
18087     invalidHandleClasses: null,
18088
18089     /**
18090      * The linked element's absolute X position at the time the drag was
18091      * started
18092      * @property startPageX
18093      * @type int
18094      * @private
18095      */
18096     startPageX: 0,
18097
18098     /**
18099      * The linked element's absolute X position at the time the drag was
18100      * started
18101      * @property startPageY
18102      * @type int
18103      * @private
18104      */
18105     startPageY: 0,
18106
18107     /**
18108      * The group defines a logical collection of DragDrop objects that are
18109      * related.  Instances only get events when interacting with other
18110      * DragDrop object in the same group.  This lets us define multiple
18111      * groups using a single DragDrop subclass if we want.
18112      * @property groups
18113      * @type {string: string}
18114      */
18115     groups: null,
18116
18117     /**
18118      * Individual drag/drop instances can be locked.  This will prevent
18119      * onmousedown start drag.
18120      * @property locked
18121      * @type boolean
18122      * @private
18123      */
18124     locked: false,
18125
18126     /**
18127      * Lock this instance
18128      * @method lock
18129      */
18130     lock: function() { this.locked = true; },
18131
18132     /**
18133      * Unlock this instace
18134      * @method unlock
18135      */
18136     unlock: function() { this.locked = false; },
18137
18138     /**
18139      * By default, all insances can be a drop target.  This can be disabled by
18140      * setting isTarget to false.
18141      * @method isTarget
18142      * @type boolean
18143      */
18144     isTarget: true,
18145
18146     /**
18147      * The padding configured for this drag and drop object for calculating
18148      * the drop zone intersection with this object.
18149      * @method padding
18150      * @type int[]
18151      */
18152     padding: null,
18153
18154     /**
18155      * Cached reference to the linked element
18156      * @property _domRef
18157      * @private
18158      */
18159     _domRef: null,
18160
18161     /**
18162      * Internal typeof flag
18163      * @property __ygDragDrop
18164      * @private
18165      */
18166     __ygDragDrop: true,
18167
18168     /**
18169      * Set to true when horizontal contraints are applied
18170      * @property constrainX
18171      * @type boolean
18172      * @private
18173      */
18174     constrainX: false,
18175
18176     /**
18177      * Set to true when vertical contraints are applied
18178      * @property constrainY
18179      * @type boolean
18180      * @private
18181      */
18182     constrainY: false,
18183
18184     /**
18185      * The left constraint
18186      * @property minX
18187      * @type int
18188      * @private
18189      */
18190     minX: 0,
18191
18192     /**
18193      * The right constraint
18194      * @property maxX
18195      * @type int
18196      * @private
18197      */
18198     maxX: 0,
18199
18200     /**
18201      * The up constraint
18202      * @property minY
18203      * @type int
18204      * @type int
18205      * @private
18206      */
18207     minY: 0,
18208
18209     /**
18210      * The down constraint
18211      * @property maxY
18212      * @type int
18213      * @private
18214      */
18215     maxY: 0,
18216
18217     /**
18218      * Maintain offsets when we resetconstraints.  Set to true when you want
18219      * the position of the element relative to its parent to stay the same
18220      * when the page changes
18221      *
18222      * @property maintainOffset
18223      * @type boolean
18224      */
18225     maintainOffset: false,
18226
18227     /**
18228      * Array of pixel locations the element will snap to if we specified a
18229      * horizontal graduation/interval.  This array is generated automatically
18230      * when you define a tick interval.
18231      * @property xTicks
18232      * @type int[]
18233      */
18234     xTicks: null,
18235
18236     /**
18237      * Array of pixel locations the element will snap to if we specified a
18238      * vertical graduation/interval.  This array is generated automatically
18239      * when you define a tick interval.
18240      * @property yTicks
18241      * @type int[]
18242      */
18243     yTicks: null,
18244
18245     /**
18246      * By default the drag and drop instance will only respond to the primary
18247      * button click (left button for a right-handed mouse).  Set to true to
18248      * allow drag and drop to start with any mouse click that is propogated
18249      * by the browser
18250      * @property primaryButtonOnly
18251      * @type boolean
18252      */
18253     primaryButtonOnly: true,
18254
18255     /**
18256      * The availabe property is false until the linked dom element is accessible.
18257      * @property available
18258      * @type boolean
18259      */
18260     available: false,
18261
18262     /**
18263      * By default, drags can only be initiated if the mousedown occurs in the
18264      * region the linked element is.  This is done in part to work around a
18265      * bug in some browsers that mis-report the mousedown if the previous
18266      * mouseup happened outside of the window.  This property is set to true
18267      * if outer handles are defined.
18268      *
18269      * @property hasOuterHandles
18270      * @type boolean
18271      * @default false
18272      */
18273     hasOuterHandles: false,
18274
18275     /**
18276      * Code that executes immediately before the startDrag event
18277      * @method b4StartDrag
18278      * @private
18279      */
18280     b4StartDrag: function(x, y) { },
18281
18282     /**
18283      * Abstract method called after a drag/drop object is clicked
18284      * and the drag or mousedown time thresholds have beeen met.
18285      * @method startDrag
18286      * @param {int} X click location
18287      * @param {int} Y click location
18288      */
18289     startDrag: function(x, y) { /* override this */ },
18290
18291     /**
18292      * Code that executes immediately before the onDrag event
18293      * @method b4Drag
18294      * @private
18295      */
18296     b4Drag: function(e) { },
18297
18298     /**
18299      * Abstract method called during the onMouseMove event while dragging an
18300      * object.
18301      * @method onDrag
18302      * @param {Event} e the mousemove event
18303      */
18304     onDrag: function(e) { /* override this */ },
18305
18306     /**
18307      * Abstract method called when this element fist begins hovering over
18308      * another DragDrop obj
18309      * @method onDragEnter
18310      * @param {Event} e the mousemove event
18311      * @param {String|DragDrop[]} id In POINT mode, the element
18312      * id this is hovering over.  In INTERSECT mode, an array of one or more
18313      * dragdrop items being hovered over.
18314      */
18315     onDragEnter: function(e, id) { /* override this */ },
18316
18317     /**
18318      * Code that executes immediately before the onDragOver event
18319      * @method b4DragOver
18320      * @private
18321      */
18322     b4DragOver: function(e) { },
18323
18324     /**
18325      * Abstract method called when this element is hovering over another
18326      * DragDrop obj
18327      * @method onDragOver
18328      * @param {Event} e the mousemove event
18329      * @param {String|DragDrop[]} id In POINT mode, the element
18330      * id this is hovering over.  In INTERSECT mode, an array of dd items
18331      * being hovered over.
18332      */
18333     onDragOver: function(e, id) { /* override this */ },
18334
18335     /**
18336      * Code that executes immediately before the onDragOut event
18337      * @method b4DragOut
18338      * @private
18339      */
18340     b4DragOut: function(e) { },
18341
18342     /**
18343      * Abstract method called when we are no longer hovering over an element
18344      * @method onDragOut
18345      * @param {Event} e the mousemove event
18346      * @param {String|DragDrop[]} id In POINT mode, the element
18347      * id this was hovering over.  In INTERSECT mode, an array of dd items
18348      * that the mouse is no longer over.
18349      */
18350     onDragOut: function(e, id) { /* override this */ },
18351
18352     /**
18353      * Code that executes immediately before the onDragDrop event
18354      * @method b4DragDrop
18355      * @private
18356      */
18357     b4DragDrop: function(e) { },
18358
18359     /**
18360      * Abstract method called when this item is dropped on another DragDrop
18361      * obj
18362      * @method onDragDrop
18363      * @param {Event} e the mouseup event
18364      * @param {String|DragDrop[]} id In POINT mode, the element
18365      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18366      * was dropped on.
18367      */
18368     onDragDrop: function(e, id) { /* override this */ },
18369
18370     /**
18371      * Abstract method called when this item is dropped on an area with no
18372      * drop target
18373      * @method onInvalidDrop
18374      * @param {Event} e the mouseup event
18375      */
18376     onInvalidDrop: function(e) { /* override this */ },
18377
18378     /**
18379      * Code that executes immediately before the endDrag event
18380      * @method b4EndDrag
18381      * @private
18382      */
18383     b4EndDrag: function(e) { },
18384
18385     /**
18386      * Fired when we are done dragging the object
18387      * @method endDrag
18388      * @param {Event} e the mouseup event
18389      */
18390     endDrag: function(e) { /* override this */ },
18391
18392     /**
18393      * Code executed immediately before the onMouseDown event
18394      * @method b4MouseDown
18395      * @param {Event} e the mousedown event
18396      * @private
18397      */
18398     b4MouseDown: function(e) {  },
18399
18400     /**
18401      * Event handler that fires when a drag/drop obj gets a mousedown
18402      * @method onMouseDown
18403      * @param {Event} e the mousedown event
18404      */
18405     onMouseDown: function(e) { /* override this */ },
18406
18407     /**
18408      * Event handler that fires when a drag/drop obj gets a mouseup
18409      * @method onMouseUp
18410      * @param {Event} e the mouseup event
18411      */
18412     onMouseUp: function(e) { /* override this */ },
18413
18414     /**
18415      * Override the onAvailable method to do what is needed after the initial
18416      * position was determined.
18417      * @method onAvailable
18418      */
18419     onAvailable: function () {
18420     },
18421
18422     /*
18423      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18424      * @type Object
18425      */
18426     defaultPadding : {left:0, right:0, top:0, bottom:0},
18427
18428     /*
18429      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18430  *
18431  * Usage:
18432  <pre><code>
18433  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18434                 { dragElId: "existingProxyDiv" });
18435  dd.startDrag = function(){
18436      this.constrainTo("parent-id");
18437  };
18438  </code></pre>
18439  * Or you can initalize it using the {@link Roo.Element} object:
18440  <pre><code>
18441  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18442      startDrag : function(){
18443          this.constrainTo("parent-id");
18444      }
18445  });
18446  </code></pre>
18447      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18448      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18449      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18450      * an object containing the sides to pad. For example: {right:10, bottom:10}
18451      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18452      */
18453     constrainTo : function(constrainTo, pad, inContent){
18454         if(typeof pad == "number"){
18455             pad = {left: pad, right:pad, top:pad, bottom:pad};
18456         }
18457         pad = pad || this.defaultPadding;
18458         var b = Roo.get(this.getEl()).getBox();
18459         var ce = Roo.get(constrainTo);
18460         var s = ce.getScroll();
18461         var c, cd = ce.dom;
18462         if(cd == document.body){
18463             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18464         }else{
18465             xy = ce.getXY();
18466             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18467         }
18468
18469
18470         var topSpace = b.y - c.y;
18471         var leftSpace = b.x - c.x;
18472
18473         this.resetConstraints();
18474         this.setXConstraint(leftSpace - (pad.left||0), // left
18475                 c.width - leftSpace - b.width - (pad.right||0) //right
18476         );
18477         this.setYConstraint(topSpace - (pad.top||0), //top
18478                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18479         );
18480     },
18481
18482     /**
18483      * Returns a reference to the linked element
18484      * @method getEl
18485      * @return {HTMLElement} the html element
18486      */
18487     getEl: function() {
18488         if (!this._domRef) {
18489             this._domRef = Roo.getDom(this.id);
18490         }
18491
18492         return this._domRef;
18493     },
18494
18495     /**
18496      * Returns a reference to the actual element to drag.  By default this is
18497      * the same as the html element, but it can be assigned to another
18498      * element. An example of this can be found in Roo.dd.DDProxy
18499      * @method getDragEl
18500      * @return {HTMLElement} the html element
18501      */
18502     getDragEl: function() {
18503         return Roo.getDom(this.dragElId);
18504     },
18505
18506     /**
18507      * Sets up the DragDrop object.  Must be called in the constructor of any
18508      * Roo.dd.DragDrop subclass
18509      * @method init
18510      * @param id the id of the linked element
18511      * @param {String} sGroup the group of related items
18512      * @param {object} config configuration attributes
18513      */
18514     init: function(id, sGroup, config) {
18515         this.initTarget(id, sGroup, config);
18516         if (!Roo.isTouch) {
18517             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18518         }
18519         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18520         // Event.on(this.id, "selectstart", Event.preventDefault);
18521     },
18522
18523     /**
18524      * Initializes Targeting functionality only... the object does not
18525      * get a mousedown handler.
18526      * @method initTarget
18527      * @param id the id of the linked element
18528      * @param {String} sGroup the group of related items
18529      * @param {object} config configuration attributes
18530      */
18531     initTarget: function(id, sGroup, config) {
18532
18533         // configuration attributes
18534         this.config = config || {};
18535
18536         // create a local reference to the drag and drop manager
18537         this.DDM = Roo.dd.DDM;
18538         // initialize the groups array
18539         this.groups = {};
18540
18541         // assume that we have an element reference instead of an id if the
18542         // parameter is not a string
18543         if (typeof id !== "string") {
18544             id = Roo.id(id);
18545         }
18546
18547         // set the id
18548         this.id = id;
18549
18550         // add to an interaction group
18551         this.addToGroup((sGroup) ? sGroup : "default");
18552
18553         // We don't want to register this as the handle with the manager
18554         // so we just set the id rather than calling the setter.
18555         this.handleElId = id;
18556
18557         // the linked element is the element that gets dragged by default
18558         this.setDragElId(id);
18559
18560         // by default, clicked anchors will not start drag operations.
18561         this.invalidHandleTypes = { A: "A" };
18562         this.invalidHandleIds = {};
18563         this.invalidHandleClasses = [];
18564
18565         this.applyConfig();
18566
18567         this.handleOnAvailable();
18568     },
18569
18570     /**
18571      * Applies the configuration parameters that were passed into the constructor.
18572      * This is supposed to happen at each level through the inheritance chain.  So
18573      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18574      * DragDrop in order to get all of the parameters that are available in
18575      * each object.
18576      * @method applyConfig
18577      */
18578     applyConfig: function() {
18579
18580         // configurable properties:
18581         //    padding, isTarget, maintainOffset, primaryButtonOnly
18582         this.padding           = this.config.padding || [0, 0, 0, 0];
18583         this.isTarget          = (this.config.isTarget !== false);
18584         this.maintainOffset    = (this.config.maintainOffset);
18585         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18586
18587     },
18588
18589     /**
18590      * Executed when the linked element is available
18591      * @method handleOnAvailable
18592      * @private
18593      */
18594     handleOnAvailable: function() {
18595         this.available = true;
18596         this.resetConstraints();
18597         this.onAvailable();
18598     },
18599
18600      /**
18601      * Configures the padding for the target zone in px.  Effectively expands
18602      * (or reduces) the virtual object size for targeting calculations.
18603      * Supports css-style shorthand; if only one parameter is passed, all sides
18604      * will have that padding, and if only two are passed, the top and bottom
18605      * will have the first param, the left and right the second.
18606      * @method setPadding
18607      * @param {int} iTop    Top pad
18608      * @param {int} iRight  Right pad
18609      * @param {int} iBot    Bot pad
18610      * @param {int} iLeft   Left pad
18611      */
18612     setPadding: function(iTop, iRight, iBot, iLeft) {
18613         // this.padding = [iLeft, iRight, iTop, iBot];
18614         if (!iRight && 0 !== iRight) {
18615             this.padding = [iTop, iTop, iTop, iTop];
18616         } else if (!iBot && 0 !== iBot) {
18617             this.padding = [iTop, iRight, iTop, iRight];
18618         } else {
18619             this.padding = [iTop, iRight, iBot, iLeft];
18620         }
18621     },
18622
18623     /**
18624      * Stores the initial placement of the linked element.
18625      * @method setInitialPosition
18626      * @param {int} diffX   the X offset, default 0
18627      * @param {int} diffY   the Y offset, default 0
18628      */
18629     setInitPosition: function(diffX, diffY) {
18630         var el = this.getEl();
18631
18632         if (!this.DDM.verifyEl(el)) {
18633             return;
18634         }
18635
18636         var dx = diffX || 0;
18637         var dy = diffY || 0;
18638
18639         var p = Dom.getXY( el );
18640
18641         this.initPageX = p[0] - dx;
18642         this.initPageY = p[1] - dy;
18643
18644         this.lastPageX = p[0];
18645         this.lastPageY = p[1];
18646
18647
18648         this.setStartPosition(p);
18649     },
18650
18651     /**
18652      * Sets the start position of the element.  This is set when the obj
18653      * is initialized, the reset when a drag is started.
18654      * @method setStartPosition
18655      * @param pos current position (from previous lookup)
18656      * @private
18657      */
18658     setStartPosition: function(pos) {
18659         var p = pos || Dom.getXY( this.getEl() );
18660         this.deltaSetXY = null;
18661
18662         this.startPageX = p[0];
18663         this.startPageY = p[1];
18664     },
18665
18666     /**
18667      * Add this instance to a group of related drag/drop objects.  All
18668      * instances belong to at least one group, and can belong to as many
18669      * groups as needed.
18670      * @method addToGroup
18671      * @param sGroup {string} the name of the group
18672      */
18673     addToGroup: function(sGroup) {
18674         this.groups[sGroup] = true;
18675         this.DDM.regDragDrop(this, sGroup);
18676     },
18677
18678     /**
18679      * Remove's this instance from the supplied interaction group
18680      * @method removeFromGroup
18681      * @param {string}  sGroup  The group to drop
18682      */
18683     removeFromGroup: function(sGroup) {
18684         if (this.groups[sGroup]) {
18685             delete this.groups[sGroup];
18686         }
18687
18688         this.DDM.removeDDFromGroup(this, sGroup);
18689     },
18690
18691     /**
18692      * Allows you to specify that an element other than the linked element
18693      * will be moved with the cursor during a drag
18694      * @method setDragElId
18695      * @param id {string} the id of the element that will be used to initiate the drag
18696      */
18697     setDragElId: function(id) {
18698         this.dragElId = id;
18699     },
18700
18701     /**
18702      * Allows you to specify a child of the linked element that should be
18703      * used to initiate the drag operation.  An example of this would be if
18704      * you have a content div with text and links.  Clicking anywhere in the
18705      * content area would normally start the drag operation.  Use this method
18706      * to specify that an element inside of the content div is the element
18707      * that starts the drag operation.
18708      * @method setHandleElId
18709      * @param id {string} the id of the element that will be used to
18710      * initiate the drag.
18711      */
18712     setHandleElId: function(id) {
18713         if (typeof id !== "string") {
18714             id = Roo.id(id);
18715         }
18716         this.handleElId = id;
18717         this.DDM.regHandle(this.id, id);
18718     },
18719
18720     /**
18721      * Allows you to set an element outside of the linked element as a drag
18722      * handle
18723      * @method setOuterHandleElId
18724      * @param id the id of the element that will be used to initiate the drag
18725      */
18726     setOuterHandleElId: function(id) {
18727         if (typeof id !== "string") {
18728             id = Roo.id(id);
18729         }
18730         Event.on(id, "mousedown",
18731                 this.handleMouseDown, this);
18732         this.setHandleElId(id);
18733
18734         this.hasOuterHandles = true;
18735     },
18736
18737     /**
18738      * Remove all drag and drop hooks for this element
18739      * @method unreg
18740      */
18741     unreg: function() {
18742         Event.un(this.id, "mousedown",
18743                 this.handleMouseDown);
18744         Event.un(this.id, "touchstart",
18745                 this.handleMouseDown);
18746         this._domRef = null;
18747         this.DDM._remove(this);
18748     },
18749
18750     destroy : function(){
18751         this.unreg();
18752     },
18753
18754     /**
18755      * Returns true if this instance is locked, or the drag drop mgr is locked
18756      * (meaning that all drag/drop is disabled on the page.)
18757      * @method isLocked
18758      * @return {boolean} true if this obj or all drag/drop is locked, else
18759      * false
18760      */
18761     isLocked: function() {
18762         return (this.DDM.isLocked() || this.locked);
18763     },
18764
18765     /**
18766      * Fired when this object is clicked
18767      * @method handleMouseDown
18768      * @param {Event} e
18769      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18770      * @private
18771      */
18772     handleMouseDown: function(e, oDD){
18773      
18774         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18775             //Roo.log('not touch/ button !=0');
18776             return;
18777         }
18778         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18779             return; // double touch..
18780         }
18781         
18782
18783         if (this.isLocked()) {
18784             //Roo.log('locked');
18785             return;
18786         }
18787
18788         this.DDM.refreshCache(this.groups);
18789 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18790         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18791         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18792             //Roo.log('no outer handes or not over target');
18793                 // do nothing.
18794         } else {
18795 //            Roo.log('check validator');
18796             if (this.clickValidator(e)) {
18797 //                Roo.log('validate success');
18798                 // set the initial element position
18799                 this.setStartPosition();
18800
18801
18802                 this.b4MouseDown(e);
18803                 this.onMouseDown(e);
18804
18805                 this.DDM.handleMouseDown(e, this);
18806
18807                 this.DDM.stopEvent(e);
18808             } else {
18809
18810
18811             }
18812         }
18813     },
18814
18815     clickValidator: function(e) {
18816         var target = e.getTarget();
18817         return ( this.isValidHandleChild(target) &&
18818                     (this.id == this.handleElId ||
18819                         this.DDM.handleWasClicked(target, this.id)) );
18820     },
18821
18822     /**
18823      * Allows you to specify a tag name that should not start a drag operation
18824      * when clicked.  This is designed to facilitate embedding links within a
18825      * drag handle that do something other than start the drag.
18826      * @method addInvalidHandleType
18827      * @param {string} tagName the type of element to exclude
18828      */
18829     addInvalidHandleType: function(tagName) {
18830         var type = tagName.toUpperCase();
18831         this.invalidHandleTypes[type] = type;
18832     },
18833
18834     /**
18835      * Lets you to specify an element id for a child of a drag handle
18836      * that should not initiate a drag
18837      * @method addInvalidHandleId
18838      * @param {string} id the element id of the element you wish to ignore
18839      */
18840     addInvalidHandleId: function(id) {
18841         if (typeof id !== "string") {
18842             id = Roo.id(id);
18843         }
18844         this.invalidHandleIds[id] = id;
18845     },
18846
18847     /**
18848      * Lets you specify a css class of elements that will not initiate a drag
18849      * @method addInvalidHandleClass
18850      * @param {string} cssClass the class of the elements you wish to ignore
18851      */
18852     addInvalidHandleClass: function(cssClass) {
18853         this.invalidHandleClasses.push(cssClass);
18854     },
18855
18856     /**
18857      * Unsets an excluded tag name set by addInvalidHandleType
18858      * @method removeInvalidHandleType
18859      * @param {string} tagName the type of element to unexclude
18860      */
18861     removeInvalidHandleType: function(tagName) {
18862         var type = tagName.toUpperCase();
18863         // this.invalidHandleTypes[type] = null;
18864         delete this.invalidHandleTypes[type];
18865     },
18866
18867     /**
18868      * Unsets an invalid handle id
18869      * @method removeInvalidHandleId
18870      * @param {string} id the id of the element to re-enable
18871      */
18872     removeInvalidHandleId: function(id) {
18873         if (typeof id !== "string") {
18874             id = Roo.id(id);
18875         }
18876         delete this.invalidHandleIds[id];
18877     },
18878
18879     /**
18880      * Unsets an invalid css class
18881      * @method removeInvalidHandleClass
18882      * @param {string} cssClass the class of the element(s) you wish to
18883      * re-enable
18884      */
18885     removeInvalidHandleClass: function(cssClass) {
18886         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18887             if (this.invalidHandleClasses[i] == cssClass) {
18888                 delete this.invalidHandleClasses[i];
18889             }
18890         }
18891     },
18892
18893     /**
18894      * Checks the tag exclusion list to see if this click should be ignored
18895      * @method isValidHandleChild
18896      * @param {HTMLElement} node the HTMLElement to evaluate
18897      * @return {boolean} true if this is a valid tag type, false if not
18898      */
18899     isValidHandleChild: function(node) {
18900
18901         var valid = true;
18902         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18903         var nodeName;
18904         try {
18905             nodeName = node.nodeName.toUpperCase();
18906         } catch(e) {
18907             nodeName = node.nodeName;
18908         }
18909         valid = valid && !this.invalidHandleTypes[nodeName];
18910         valid = valid && !this.invalidHandleIds[node.id];
18911
18912         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18913             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18914         }
18915
18916
18917         return valid;
18918
18919     },
18920
18921     /**
18922      * Create the array of horizontal tick marks if an interval was specified
18923      * in setXConstraint().
18924      * @method setXTicks
18925      * @private
18926      */
18927     setXTicks: function(iStartX, iTickSize) {
18928         this.xTicks = [];
18929         this.xTickSize = iTickSize;
18930
18931         var tickMap = {};
18932
18933         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18934             if (!tickMap[i]) {
18935                 this.xTicks[this.xTicks.length] = i;
18936                 tickMap[i] = true;
18937             }
18938         }
18939
18940         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18941             if (!tickMap[i]) {
18942                 this.xTicks[this.xTicks.length] = i;
18943                 tickMap[i] = true;
18944             }
18945         }
18946
18947         this.xTicks.sort(this.DDM.numericSort) ;
18948     },
18949
18950     /**
18951      * Create the array of vertical tick marks if an interval was specified in
18952      * setYConstraint().
18953      * @method setYTicks
18954      * @private
18955      */
18956     setYTicks: function(iStartY, iTickSize) {
18957         this.yTicks = [];
18958         this.yTickSize = iTickSize;
18959
18960         var tickMap = {};
18961
18962         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18963             if (!tickMap[i]) {
18964                 this.yTicks[this.yTicks.length] = i;
18965                 tickMap[i] = true;
18966             }
18967         }
18968
18969         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18970             if (!tickMap[i]) {
18971                 this.yTicks[this.yTicks.length] = i;
18972                 tickMap[i] = true;
18973             }
18974         }
18975
18976         this.yTicks.sort(this.DDM.numericSort) ;
18977     },
18978
18979     /**
18980      * By default, the element can be dragged any place on the screen.  Use
18981      * this method to limit the horizontal travel of the element.  Pass in
18982      * 0,0 for the parameters if you want to lock the drag to the y axis.
18983      * @method setXConstraint
18984      * @param {int} iLeft the number of pixels the element can move to the left
18985      * @param {int} iRight the number of pixels the element can move to the
18986      * right
18987      * @param {int} iTickSize optional parameter for specifying that the
18988      * element
18989      * should move iTickSize pixels at a time.
18990      */
18991     setXConstraint: function(iLeft, iRight, iTickSize) {
18992         this.leftConstraint = iLeft;
18993         this.rightConstraint = iRight;
18994
18995         this.minX = this.initPageX - iLeft;
18996         this.maxX = this.initPageX + iRight;
18997         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18998
18999         this.constrainX = true;
19000     },
19001
19002     /**
19003      * Clears any constraints applied to this instance.  Also clears ticks
19004      * since they can't exist independent of a constraint at this time.
19005      * @method clearConstraints
19006      */
19007     clearConstraints: function() {
19008         this.constrainX = false;
19009         this.constrainY = false;
19010         this.clearTicks();
19011     },
19012
19013     /**
19014      * Clears any tick interval defined for this instance
19015      * @method clearTicks
19016      */
19017     clearTicks: function() {
19018         this.xTicks = null;
19019         this.yTicks = null;
19020         this.xTickSize = 0;
19021         this.yTickSize = 0;
19022     },
19023
19024     /**
19025      * By default, the element can be dragged any place on the screen.  Set
19026      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19027      * parameters if you want to lock the drag to the x axis.
19028      * @method setYConstraint
19029      * @param {int} iUp the number of pixels the element can move up
19030      * @param {int} iDown the number of pixels the element can move down
19031      * @param {int} iTickSize optional parameter for specifying that the
19032      * element should move iTickSize pixels at a time.
19033      */
19034     setYConstraint: function(iUp, iDown, iTickSize) {
19035         this.topConstraint = iUp;
19036         this.bottomConstraint = iDown;
19037
19038         this.minY = this.initPageY - iUp;
19039         this.maxY = this.initPageY + iDown;
19040         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19041
19042         this.constrainY = true;
19043
19044     },
19045
19046     /**
19047      * resetConstraints must be called if you manually reposition a dd element.
19048      * @method resetConstraints
19049      * @param {boolean} maintainOffset
19050      */
19051     resetConstraints: function() {
19052
19053
19054         // Maintain offsets if necessary
19055         if (this.initPageX || this.initPageX === 0) {
19056             // figure out how much this thing has moved
19057             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19058             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19059
19060             this.setInitPosition(dx, dy);
19061
19062         // This is the first time we have detected the element's position
19063         } else {
19064             this.setInitPosition();
19065         }
19066
19067         if (this.constrainX) {
19068             this.setXConstraint( this.leftConstraint,
19069                                  this.rightConstraint,
19070                                  this.xTickSize        );
19071         }
19072
19073         if (this.constrainY) {
19074             this.setYConstraint( this.topConstraint,
19075                                  this.bottomConstraint,
19076                                  this.yTickSize         );
19077         }
19078     },
19079
19080     /**
19081      * Normally the drag element is moved pixel by pixel, but we can specify
19082      * that it move a number of pixels at a time.  This method resolves the
19083      * location when we have it set up like this.
19084      * @method getTick
19085      * @param {int} val where we want to place the object
19086      * @param {int[]} tickArray sorted array of valid points
19087      * @return {int} the closest tick
19088      * @private
19089      */
19090     getTick: function(val, tickArray) {
19091
19092         if (!tickArray) {
19093             // If tick interval is not defined, it is effectively 1 pixel,
19094             // so we return the value passed to us.
19095             return val;
19096         } else if (tickArray[0] >= val) {
19097             // The value is lower than the first tick, so we return the first
19098             // tick.
19099             return tickArray[0];
19100         } else {
19101             for (var i=0, len=tickArray.length; i<len; ++i) {
19102                 var next = i + 1;
19103                 if (tickArray[next] && tickArray[next] >= val) {
19104                     var diff1 = val - tickArray[i];
19105                     var diff2 = tickArray[next] - val;
19106                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19107                 }
19108             }
19109
19110             // The value is larger than the last tick, so we return the last
19111             // tick.
19112             return tickArray[tickArray.length - 1];
19113         }
19114     },
19115
19116     /**
19117      * toString method
19118      * @method toString
19119      * @return {string} string representation of the dd obj
19120      */
19121     toString: function() {
19122         return ("DragDrop " + this.id);
19123     }
19124
19125 });
19126
19127 })();
19128 /*
19129  * Based on:
19130  * Ext JS Library 1.1.1
19131  * Copyright(c) 2006-2007, Ext JS, LLC.
19132  *
19133  * Originally Released Under LGPL - original licence link has changed is not relivant.
19134  *
19135  * Fork - LGPL
19136  * <script type="text/javascript">
19137  */
19138
19139
19140 /**
19141  * The drag and drop utility provides a framework for building drag and drop
19142  * applications.  In addition to enabling drag and drop for specific elements,
19143  * the drag and drop elements are tracked by the manager class, and the
19144  * interactions between the various elements are tracked during the drag and
19145  * the implementing code is notified about these important moments.
19146  */
19147
19148 // Only load the library once.  Rewriting the manager class would orphan
19149 // existing drag and drop instances.
19150 if (!Roo.dd.DragDropMgr) {
19151
19152 /**
19153  * @class Roo.dd.DragDropMgr
19154  * DragDropMgr is a singleton that tracks the element interaction for
19155  * all DragDrop items in the window.  Generally, you will not call
19156  * this class directly, but it does have helper methods that could
19157  * be useful in your DragDrop implementations.
19158  * @singleton
19159  */
19160 Roo.dd.DragDropMgr = function() {
19161
19162     var Event = Roo.EventManager;
19163
19164     return {
19165
19166         /**
19167          * Two dimensional Array of registered DragDrop objects.  The first
19168          * dimension is the DragDrop item group, the second the DragDrop
19169          * object.
19170          * @property ids
19171          * @type {string: string}
19172          * @private
19173          * @static
19174          */
19175         ids: {},
19176
19177         /**
19178          * Array of element ids defined as drag handles.  Used to determine
19179          * if the element that generated the mousedown event is actually the
19180          * handle and not the html element itself.
19181          * @property handleIds
19182          * @type {string: string}
19183          * @private
19184          * @static
19185          */
19186         handleIds: {},
19187
19188         /**
19189          * the DragDrop object that is currently being dragged
19190          * @property dragCurrent
19191          * @type DragDrop
19192          * @private
19193          * @static
19194          **/
19195         dragCurrent: null,
19196
19197         /**
19198          * the DragDrop object(s) that are being hovered over
19199          * @property dragOvers
19200          * @type Array
19201          * @private
19202          * @static
19203          */
19204         dragOvers: {},
19205
19206         /**
19207          * the X distance between the cursor and the object being dragged
19208          * @property deltaX
19209          * @type int
19210          * @private
19211          * @static
19212          */
19213         deltaX: 0,
19214
19215         /**
19216          * the Y distance between the cursor and the object being dragged
19217          * @property deltaY
19218          * @type int
19219          * @private
19220          * @static
19221          */
19222         deltaY: 0,
19223
19224         /**
19225          * Flag to determine if we should prevent the default behavior of the
19226          * events we define. By default this is true, but this can be set to
19227          * false if you need the default behavior (not recommended)
19228          * @property preventDefault
19229          * @type boolean
19230          * @static
19231          */
19232         preventDefault: true,
19233
19234         /**
19235          * Flag to determine if we should stop the propagation of the events
19236          * we generate. This is true by default but you may want to set it to
19237          * false if the html element contains other features that require the
19238          * mouse click.
19239          * @property stopPropagation
19240          * @type boolean
19241          * @static
19242          */
19243         stopPropagation: true,
19244
19245         /**
19246          * Internal flag that is set to true when drag and drop has been
19247          * intialized
19248          * @property initialized
19249          * @private
19250          * @static
19251          */
19252         initalized: false,
19253
19254         /**
19255          * All drag and drop can be disabled.
19256          * @property locked
19257          * @private
19258          * @static
19259          */
19260         locked: false,
19261
19262         /**
19263          * Called the first time an element is registered.
19264          * @method init
19265          * @private
19266          * @static
19267          */
19268         init: function() {
19269             this.initialized = true;
19270         },
19271
19272         /**
19273          * In point mode, drag and drop interaction is defined by the
19274          * location of the cursor during the drag/drop
19275          * @property POINT
19276          * @type int
19277          * @static
19278          */
19279         POINT: 0,
19280
19281         /**
19282          * In intersect mode, drag and drop interactio nis defined by the
19283          * overlap of two or more drag and drop objects.
19284          * @property INTERSECT
19285          * @type int
19286          * @static
19287          */
19288         INTERSECT: 1,
19289
19290         /**
19291          * The current drag and drop mode.  Default: POINT
19292          * @property mode
19293          * @type int
19294          * @static
19295          */
19296         mode: 0,
19297
19298         /**
19299          * Runs method on all drag and drop objects
19300          * @method _execOnAll
19301          * @private
19302          * @static
19303          */
19304         _execOnAll: function(sMethod, args) {
19305             for (var i in this.ids) {
19306                 for (var j in this.ids[i]) {
19307                     var oDD = this.ids[i][j];
19308                     if (! this.isTypeOfDD(oDD)) {
19309                         continue;
19310                     }
19311                     oDD[sMethod].apply(oDD, args);
19312                 }
19313             }
19314         },
19315
19316         /**
19317          * Drag and drop initialization.  Sets up the global event handlers
19318          * @method _onLoad
19319          * @private
19320          * @static
19321          */
19322         _onLoad: function() {
19323
19324             this.init();
19325
19326             if (!Roo.isTouch) {
19327                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19328                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19329             }
19330             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19331             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19332             
19333             Event.on(window,   "unload",    this._onUnload, this, true);
19334             Event.on(window,   "resize",    this._onResize, this, true);
19335             // Event.on(window,   "mouseout",    this._test);
19336
19337         },
19338
19339         /**
19340          * Reset constraints on all drag and drop objs
19341          * @method _onResize
19342          * @private
19343          * @static
19344          */
19345         _onResize: function(e) {
19346             this._execOnAll("resetConstraints", []);
19347         },
19348
19349         /**
19350          * Lock all drag and drop functionality
19351          * @method lock
19352          * @static
19353          */
19354         lock: function() { this.locked = true; },
19355
19356         /**
19357          * Unlock all drag and drop functionality
19358          * @method unlock
19359          * @static
19360          */
19361         unlock: function() { this.locked = false; },
19362
19363         /**
19364          * Is drag and drop locked?
19365          * @method isLocked
19366          * @return {boolean} True if drag and drop is locked, false otherwise.
19367          * @static
19368          */
19369         isLocked: function() { return this.locked; },
19370
19371         /**
19372          * Location cache that is set for all drag drop objects when a drag is
19373          * initiated, cleared when the drag is finished.
19374          * @property locationCache
19375          * @private
19376          * @static
19377          */
19378         locationCache: {},
19379
19380         /**
19381          * Set useCache to false if you want to force object the lookup of each
19382          * drag and drop linked element constantly during a drag.
19383          * @property useCache
19384          * @type boolean
19385          * @static
19386          */
19387         useCache: true,
19388
19389         /**
19390          * The number of pixels that the mouse needs to move after the
19391          * mousedown before the drag is initiated.  Default=3;
19392          * @property clickPixelThresh
19393          * @type int
19394          * @static
19395          */
19396         clickPixelThresh: 3,
19397
19398         /**
19399          * The number of milliseconds after the mousedown event to initiate the
19400          * drag if we don't get a mouseup event. Default=1000
19401          * @property clickTimeThresh
19402          * @type int
19403          * @static
19404          */
19405         clickTimeThresh: 350,
19406
19407         /**
19408          * Flag that indicates that either the drag pixel threshold or the
19409          * mousdown time threshold has been met
19410          * @property dragThreshMet
19411          * @type boolean
19412          * @private
19413          * @static
19414          */
19415         dragThreshMet: false,
19416
19417         /**
19418          * Timeout used for the click time threshold
19419          * @property clickTimeout
19420          * @type Object
19421          * @private
19422          * @static
19423          */
19424         clickTimeout: null,
19425
19426         /**
19427          * The X position of the mousedown event stored for later use when a
19428          * drag threshold is met.
19429          * @property startX
19430          * @type int
19431          * @private
19432          * @static
19433          */
19434         startX: 0,
19435
19436         /**
19437          * The Y position of the mousedown event stored for later use when a
19438          * drag threshold is met.
19439          * @property startY
19440          * @type int
19441          * @private
19442          * @static
19443          */
19444         startY: 0,
19445
19446         /**
19447          * Each DragDrop instance must be registered with the DragDropMgr.
19448          * This is executed in DragDrop.init()
19449          * @method regDragDrop
19450          * @param {DragDrop} oDD the DragDrop object to register
19451          * @param {String} sGroup the name of the group this element belongs to
19452          * @static
19453          */
19454         regDragDrop: function(oDD, sGroup) {
19455             if (!this.initialized) { this.init(); }
19456
19457             if (!this.ids[sGroup]) {
19458                 this.ids[sGroup] = {};
19459             }
19460             this.ids[sGroup][oDD.id] = oDD;
19461         },
19462
19463         /**
19464          * Removes the supplied dd instance from the supplied group. Executed
19465          * by DragDrop.removeFromGroup, so don't call this function directly.
19466          * @method removeDDFromGroup
19467          * @private
19468          * @static
19469          */
19470         removeDDFromGroup: function(oDD, sGroup) {
19471             if (!this.ids[sGroup]) {
19472                 this.ids[sGroup] = {};
19473             }
19474
19475             var obj = this.ids[sGroup];
19476             if (obj && obj[oDD.id]) {
19477                 delete obj[oDD.id];
19478             }
19479         },
19480
19481         /**
19482          * Unregisters a drag and drop item.  This is executed in
19483          * DragDrop.unreg, use that method instead of calling this directly.
19484          * @method _remove
19485          * @private
19486          * @static
19487          */
19488         _remove: function(oDD) {
19489             for (var g in oDD.groups) {
19490                 if (g && this.ids[g][oDD.id]) {
19491                     delete this.ids[g][oDD.id];
19492                 }
19493             }
19494             delete this.handleIds[oDD.id];
19495         },
19496
19497         /**
19498          * Each DragDrop handle element must be registered.  This is done
19499          * automatically when executing DragDrop.setHandleElId()
19500          * @method regHandle
19501          * @param {String} sDDId the DragDrop id this element is a handle for
19502          * @param {String} sHandleId the id of the element that is the drag
19503          * handle
19504          * @static
19505          */
19506         regHandle: function(sDDId, sHandleId) {
19507             if (!this.handleIds[sDDId]) {
19508                 this.handleIds[sDDId] = {};
19509             }
19510             this.handleIds[sDDId][sHandleId] = sHandleId;
19511         },
19512
19513         /**
19514          * Utility function to determine if a given element has been
19515          * registered as a drag drop item.
19516          * @method isDragDrop
19517          * @param {String} id the element id to check
19518          * @return {boolean} true if this element is a DragDrop item,
19519          * false otherwise
19520          * @static
19521          */
19522         isDragDrop: function(id) {
19523             return ( this.getDDById(id) ) ? true : false;
19524         },
19525
19526         /**
19527          * Returns the drag and drop instances that are in all groups the
19528          * passed in instance belongs to.
19529          * @method getRelated
19530          * @param {DragDrop} p_oDD the obj to get related data for
19531          * @param {boolean} bTargetsOnly if true, only return targetable objs
19532          * @return {DragDrop[]} the related instances
19533          * @static
19534          */
19535         getRelated: function(p_oDD, bTargetsOnly) {
19536             var oDDs = [];
19537             for (var i in p_oDD.groups) {
19538                 for (j in this.ids[i]) {
19539                     var dd = this.ids[i][j];
19540                     if (! this.isTypeOfDD(dd)) {
19541                         continue;
19542                     }
19543                     if (!bTargetsOnly || dd.isTarget) {
19544                         oDDs[oDDs.length] = dd;
19545                     }
19546                 }
19547             }
19548
19549             return oDDs;
19550         },
19551
19552         /**
19553          * Returns true if the specified dd target is a legal target for
19554          * the specifice drag obj
19555          * @method isLegalTarget
19556          * @param {DragDrop} the drag obj
19557          * @param {DragDrop} the target
19558          * @return {boolean} true if the target is a legal target for the
19559          * dd obj
19560          * @static
19561          */
19562         isLegalTarget: function (oDD, oTargetDD) {
19563             var targets = this.getRelated(oDD, true);
19564             for (var i=0, len=targets.length;i<len;++i) {
19565                 if (targets[i].id == oTargetDD.id) {
19566                     return true;
19567                 }
19568             }
19569
19570             return false;
19571         },
19572
19573         /**
19574          * My goal is to be able to transparently determine if an object is
19575          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19576          * returns "object", oDD.constructor.toString() always returns
19577          * "DragDrop" and not the name of the subclass.  So for now it just
19578          * evaluates a well-known variable in DragDrop.
19579          * @method isTypeOfDD
19580          * @param {Object} the object to evaluate
19581          * @return {boolean} true if typeof oDD = DragDrop
19582          * @static
19583          */
19584         isTypeOfDD: function (oDD) {
19585             return (oDD && oDD.__ygDragDrop);
19586         },
19587
19588         /**
19589          * Utility function to determine if a given element has been
19590          * registered as a drag drop handle for the given Drag Drop object.
19591          * @method isHandle
19592          * @param {String} id the element id to check
19593          * @return {boolean} true if this element is a DragDrop handle, false
19594          * otherwise
19595          * @static
19596          */
19597         isHandle: function(sDDId, sHandleId) {
19598             return ( this.handleIds[sDDId] &&
19599                             this.handleIds[sDDId][sHandleId] );
19600         },
19601
19602         /**
19603          * Returns the DragDrop instance for a given id
19604          * @method getDDById
19605          * @param {String} id the id of the DragDrop object
19606          * @return {DragDrop} the drag drop object, null if it is not found
19607          * @static
19608          */
19609         getDDById: function(id) {
19610             for (var i in this.ids) {
19611                 if (this.ids[i][id]) {
19612                     return this.ids[i][id];
19613                 }
19614             }
19615             return null;
19616         },
19617
19618         /**
19619          * Fired after a registered DragDrop object gets the mousedown event.
19620          * Sets up the events required to track the object being dragged
19621          * @method handleMouseDown
19622          * @param {Event} e the event
19623          * @param oDD the DragDrop object being dragged
19624          * @private
19625          * @static
19626          */
19627         handleMouseDown: function(e, oDD) {
19628             if(Roo.QuickTips){
19629                 Roo.QuickTips.disable();
19630             }
19631             this.currentTarget = e.getTarget();
19632
19633             this.dragCurrent = oDD;
19634
19635             var el = oDD.getEl();
19636
19637             // track start position
19638             this.startX = e.getPageX();
19639             this.startY = e.getPageY();
19640
19641             this.deltaX = this.startX - el.offsetLeft;
19642             this.deltaY = this.startY - el.offsetTop;
19643
19644             this.dragThreshMet = false;
19645
19646             this.clickTimeout = setTimeout(
19647                     function() {
19648                         var DDM = Roo.dd.DDM;
19649                         DDM.startDrag(DDM.startX, DDM.startY);
19650                     },
19651                     this.clickTimeThresh );
19652         },
19653
19654         /**
19655          * Fired when either the drag pixel threshol or the mousedown hold
19656          * time threshold has been met.
19657          * @method startDrag
19658          * @param x {int} the X position of the original mousedown
19659          * @param y {int} the Y position of the original mousedown
19660          * @static
19661          */
19662         startDrag: function(x, y) {
19663             clearTimeout(this.clickTimeout);
19664             if (this.dragCurrent) {
19665                 this.dragCurrent.b4StartDrag(x, y);
19666                 this.dragCurrent.startDrag(x, y);
19667             }
19668             this.dragThreshMet = true;
19669         },
19670
19671         /**
19672          * Internal function to handle the mouseup event.  Will be invoked
19673          * from the context of the document.
19674          * @method handleMouseUp
19675          * @param {Event} e the event
19676          * @private
19677          * @static
19678          */
19679         handleMouseUp: function(e) {
19680
19681             if(Roo.QuickTips){
19682                 Roo.QuickTips.enable();
19683             }
19684             if (! this.dragCurrent) {
19685                 return;
19686             }
19687
19688             clearTimeout(this.clickTimeout);
19689
19690             if (this.dragThreshMet) {
19691                 this.fireEvents(e, true);
19692             } else {
19693             }
19694
19695             this.stopDrag(e);
19696
19697             this.stopEvent(e);
19698         },
19699
19700         /**
19701          * Utility to stop event propagation and event default, if these
19702          * features are turned on.
19703          * @method stopEvent
19704          * @param {Event} e the event as returned by this.getEvent()
19705          * @static
19706          */
19707         stopEvent: function(e){
19708             if(this.stopPropagation) {
19709                 e.stopPropagation();
19710             }
19711
19712             if (this.preventDefault) {
19713                 e.preventDefault();
19714             }
19715         },
19716
19717         /**
19718          * Internal function to clean up event handlers after the drag
19719          * operation is complete
19720          * @method stopDrag
19721          * @param {Event} e the event
19722          * @private
19723          * @static
19724          */
19725         stopDrag: function(e) {
19726             // Fire the drag end event for the item that was dragged
19727             if (this.dragCurrent) {
19728                 if (this.dragThreshMet) {
19729                     this.dragCurrent.b4EndDrag(e);
19730                     this.dragCurrent.endDrag(e);
19731                 }
19732
19733                 this.dragCurrent.onMouseUp(e);
19734             }
19735
19736             this.dragCurrent = null;
19737             this.dragOvers = {};
19738         },
19739
19740         /**
19741          * Internal function to handle the mousemove event.  Will be invoked
19742          * from the context of the html element.
19743          *
19744          * @TODO figure out what we can do about mouse events lost when the
19745          * user drags objects beyond the window boundary.  Currently we can
19746          * detect this in internet explorer by verifying that the mouse is
19747          * down during the mousemove event.  Firefox doesn't give us the
19748          * button state on the mousemove event.
19749          * @method handleMouseMove
19750          * @param {Event} e the event
19751          * @private
19752          * @static
19753          */
19754         handleMouseMove: function(e) {
19755             if (! this.dragCurrent) {
19756                 return true;
19757             }
19758
19759             // var button = e.which || e.button;
19760
19761             // check for IE mouseup outside of page boundary
19762             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19763                 this.stopEvent(e);
19764                 return this.handleMouseUp(e);
19765             }
19766
19767             if (!this.dragThreshMet) {
19768                 var diffX = Math.abs(this.startX - e.getPageX());
19769                 var diffY = Math.abs(this.startY - e.getPageY());
19770                 if (diffX > this.clickPixelThresh ||
19771                             diffY > this.clickPixelThresh) {
19772                     this.startDrag(this.startX, this.startY);
19773                 }
19774             }
19775
19776             if (this.dragThreshMet) {
19777                 this.dragCurrent.b4Drag(e);
19778                 this.dragCurrent.onDrag(e);
19779                 if(!this.dragCurrent.moveOnly){
19780                     this.fireEvents(e, false);
19781                 }
19782             }
19783
19784             this.stopEvent(e);
19785
19786             return true;
19787         },
19788
19789         /**
19790          * Iterates over all of the DragDrop elements to find ones we are
19791          * hovering over or dropping on
19792          * @method fireEvents
19793          * @param {Event} e the event
19794          * @param {boolean} isDrop is this a drop op or a mouseover op?
19795          * @private
19796          * @static
19797          */
19798         fireEvents: function(e, isDrop) {
19799             var dc = this.dragCurrent;
19800
19801             // If the user did the mouse up outside of the window, we could
19802             // get here even though we have ended the drag.
19803             if (!dc || dc.isLocked()) {
19804                 return;
19805             }
19806
19807             var pt = e.getPoint();
19808
19809             // cache the previous dragOver array
19810             var oldOvers = [];
19811
19812             var outEvts   = [];
19813             var overEvts  = [];
19814             var dropEvts  = [];
19815             var enterEvts = [];
19816
19817             // Check to see if the object(s) we were hovering over is no longer
19818             // being hovered over so we can fire the onDragOut event
19819             for (var i in this.dragOvers) {
19820
19821                 var ddo = this.dragOvers[i];
19822
19823                 if (! this.isTypeOfDD(ddo)) {
19824                     continue;
19825                 }
19826
19827                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19828                     outEvts.push( ddo );
19829                 }
19830
19831                 oldOvers[i] = true;
19832                 delete this.dragOvers[i];
19833             }
19834
19835             for (var sGroup in dc.groups) {
19836
19837                 if ("string" != typeof sGroup) {
19838                     continue;
19839                 }
19840
19841                 for (i in this.ids[sGroup]) {
19842                     var oDD = this.ids[sGroup][i];
19843                     if (! this.isTypeOfDD(oDD)) {
19844                         continue;
19845                     }
19846
19847                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19848                         if (this.isOverTarget(pt, oDD, this.mode)) {
19849                             // look for drop interactions
19850                             if (isDrop) {
19851                                 dropEvts.push( oDD );
19852                             // look for drag enter and drag over interactions
19853                             } else {
19854
19855                                 // initial drag over: dragEnter fires
19856                                 if (!oldOvers[oDD.id]) {
19857                                     enterEvts.push( oDD );
19858                                 // subsequent drag overs: dragOver fires
19859                                 } else {
19860                                     overEvts.push( oDD );
19861                                 }
19862
19863                                 this.dragOvers[oDD.id] = oDD;
19864                             }
19865                         }
19866                     }
19867                 }
19868             }
19869
19870             if (this.mode) {
19871                 if (outEvts.length) {
19872                     dc.b4DragOut(e, outEvts);
19873                     dc.onDragOut(e, outEvts);
19874                 }
19875
19876                 if (enterEvts.length) {
19877                     dc.onDragEnter(e, enterEvts);
19878                 }
19879
19880                 if (overEvts.length) {
19881                     dc.b4DragOver(e, overEvts);
19882                     dc.onDragOver(e, overEvts);
19883                 }
19884
19885                 if (dropEvts.length) {
19886                     dc.b4DragDrop(e, dropEvts);
19887                     dc.onDragDrop(e, dropEvts);
19888                 }
19889
19890             } else {
19891                 // fire dragout events
19892                 var len = 0;
19893                 for (i=0, len=outEvts.length; i<len; ++i) {
19894                     dc.b4DragOut(e, outEvts[i].id);
19895                     dc.onDragOut(e, outEvts[i].id);
19896                 }
19897
19898                 // fire enter events
19899                 for (i=0,len=enterEvts.length; i<len; ++i) {
19900                     // dc.b4DragEnter(e, oDD.id);
19901                     dc.onDragEnter(e, enterEvts[i].id);
19902                 }
19903
19904                 // fire over events
19905                 for (i=0,len=overEvts.length; i<len; ++i) {
19906                     dc.b4DragOver(e, overEvts[i].id);
19907                     dc.onDragOver(e, overEvts[i].id);
19908                 }
19909
19910                 // fire drop events
19911                 for (i=0, len=dropEvts.length; i<len; ++i) {
19912                     dc.b4DragDrop(e, dropEvts[i].id);
19913                     dc.onDragDrop(e, dropEvts[i].id);
19914                 }
19915
19916             }
19917
19918             // notify about a drop that did not find a target
19919             if (isDrop && !dropEvts.length) {
19920                 dc.onInvalidDrop(e);
19921             }
19922
19923         },
19924
19925         /**
19926          * Helper function for getting the best match from the list of drag
19927          * and drop objects returned by the drag and drop events when we are
19928          * in INTERSECT mode.  It returns either the first object that the
19929          * cursor is over, or the object that has the greatest overlap with
19930          * the dragged element.
19931          * @method getBestMatch
19932          * @param  {DragDrop[]} dds The array of drag and drop objects
19933          * targeted
19934          * @return {DragDrop}       The best single match
19935          * @static
19936          */
19937         getBestMatch: function(dds) {
19938             var winner = null;
19939             // Return null if the input is not what we expect
19940             //if (!dds || !dds.length || dds.length == 0) {
19941                // winner = null;
19942             // If there is only one item, it wins
19943             //} else if (dds.length == 1) {
19944
19945             var len = dds.length;
19946
19947             if (len == 1) {
19948                 winner = dds[0];
19949             } else {
19950                 // Loop through the targeted items
19951                 for (var i=0; i<len; ++i) {
19952                     var dd = dds[i];
19953                     // If the cursor is over the object, it wins.  If the
19954                     // cursor is over multiple matches, the first one we come
19955                     // to wins.
19956                     if (dd.cursorIsOver) {
19957                         winner = dd;
19958                         break;
19959                     // Otherwise the object with the most overlap wins
19960                     } else {
19961                         if (!winner ||
19962                             winner.overlap.getArea() < dd.overlap.getArea()) {
19963                             winner = dd;
19964                         }
19965                     }
19966                 }
19967             }
19968
19969             return winner;
19970         },
19971
19972         /**
19973          * Refreshes the cache of the top-left and bottom-right points of the
19974          * drag and drop objects in the specified group(s).  This is in the
19975          * format that is stored in the drag and drop instance, so typical
19976          * usage is:
19977          * <code>
19978          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19979          * </code>
19980          * Alternatively:
19981          * <code>
19982          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19983          * </code>
19984          * @TODO this really should be an indexed array.  Alternatively this
19985          * method could accept both.
19986          * @method refreshCache
19987          * @param {Object} groups an associative array of groups to refresh
19988          * @static
19989          */
19990         refreshCache: function(groups) {
19991             for (var sGroup in groups) {
19992                 if ("string" != typeof sGroup) {
19993                     continue;
19994                 }
19995                 for (var i in this.ids[sGroup]) {
19996                     var oDD = this.ids[sGroup][i];
19997
19998                     if (this.isTypeOfDD(oDD)) {
19999                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20000                         var loc = this.getLocation(oDD);
20001                         if (loc) {
20002                             this.locationCache[oDD.id] = loc;
20003                         } else {
20004                             delete this.locationCache[oDD.id];
20005                             // this will unregister the drag and drop object if
20006                             // the element is not in a usable state
20007                             // oDD.unreg();
20008                         }
20009                     }
20010                 }
20011             }
20012         },
20013
20014         /**
20015          * This checks to make sure an element exists and is in the DOM.  The
20016          * main purpose is to handle cases where innerHTML is used to remove
20017          * drag and drop objects from the DOM.  IE provides an 'unspecified
20018          * error' when trying to access the offsetParent of such an element
20019          * @method verifyEl
20020          * @param {HTMLElement} el the element to check
20021          * @return {boolean} true if the element looks usable
20022          * @static
20023          */
20024         verifyEl: function(el) {
20025             if (el) {
20026                 var parent;
20027                 if(Roo.isIE){
20028                     try{
20029                         parent = el.offsetParent;
20030                     }catch(e){}
20031                 }else{
20032                     parent = el.offsetParent;
20033                 }
20034                 if (parent) {
20035                     return true;
20036                 }
20037             }
20038
20039             return false;
20040         },
20041
20042         /**
20043          * Returns a Region object containing the drag and drop element's position
20044          * and size, including the padding configured for it
20045          * @method getLocation
20046          * @param {DragDrop} oDD the drag and drop object to get the
20047          *                       location for
20048          * @return {Roo.lib.Region} a Region object representing the total area
20049          *                             the element occupies, including any padding
20050          *                             the instance is configured for.
20051          * @static
20052          */
20053         getLocation: function(oDD) {
20054             if (! this.isTypeOfDD(oDD)) {
20055                 return null;
20056             }
20057
20058             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20059
20060             try {
20061                 pos= Roo.lib.Dom.getXY(el);
20062             } catch (e) { }
20063
20064             if (!pos) {
20065                 return null;
20066             }
20067
20068             x1 = pos[0];
20069             x2 = x1 + el.offsetWidth;
20070             y1 = pos[1];
20071             y2 = y1 + el.offsetHeight;
20072
20073             t = y1 - oDD.padding[0];
20074             r = x2 + oDD.padding[1];
20075             b = y2 + oDD.padding[2];
20076             l = x1 - oDD.padding[3];
20077
20078             return new Roo.lib.Region( t, r, b, l );
20079         },
20080
20081         /**
20082          * Checks the cursor location to see if it over the target
20083          * @method isOverTarget
20084          * @param {Roo.lib.Point} pt The point to evaluate
20085          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20086          * @return {boolean} true if the mouse is over the target
20087          * @private
20088          * @static
20089          */
20090         isOverTarget: function(pt, oTarget, intersect) {
20091             // use cache if available
20092             var loc = this.locationCache[oTarget.id];
20093             if (!loc || !this.useCache) {
20094                 loc = this.getLocation(oTarget);
20095                 this.locationCache[oTarget.id] = loc;
20096
20097             }
20098
20099             if (!loc) {
20100                 return false;
20101             }
20102
20103             oTarget.cursorIsOver = loc.contains( pt );
20104
20105             // DragDrop is using this as a sanity check for the initial mousedown
20106             // in this case we are done.  In POINT mode, if the drag obj has no
20107             // contraints, we are also done. Otherwise we need to evaluate the
20108             // location of the target as related to the actual location of the
20109             // dragged element.
20110             var dc = this.dragCurrent;
20111             if (!dc || !dc.getTargetCoord ||
20112                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20113                 return oTarget.cursorIsOver;
20114             }
20115
20116             oTarget.overlap = null;
20117
20118             // Get the current location of the drag element, this is the
20119             // location of the mouse event less the delta that represents
20120             // where the original mousedown happened on the element.  We
20121             // need to consider constraints and ticks as well.
20122             var pos = dc.getTargetCoord(pt.x, pt.y);
20123
20124             var el = dc.getDragEl();
20125             var curRegion = new Roo.lib.Region( pos.y,
20126                                                    pos.x + el.offsetWidth,
20127                                                    pos.y + el.offsetHeight,
20128                                                    pos.x );
20129
20130             var overlap = curRegion.intersect(loc);
20131
20132             if (overlap) {
20133                 oTarget.overlap = overlap;
20134                 return (intersect) ? true : oTarget.cursorIsOver;
20135             } else {
20136                 return false;
20137             }
20138         },
20139
20140         /**
20141          * unload event handler
20142          * @method _onUnload
20143          * @private
20144          * @static
20145          */
20146         _onUnload: function(e, me) {
20147             Roo.dd.DragDropMgr.unregAll();
20148         },
20149
20150         /**
20151          * Cleans up the drag and drop events and objects.
20152          * @method unregAll
20153          * @private
20154          * @static
20155          */
20156         unregAll: function() {
20157
20158             if (this.dragCurrent) {
20159                 this.stopDrag();
20160                 this.dragCurrent = null;
20161             }
20162
20163             this._execOnAll("unreg", []);
20164
20165             for (i in this.elementCache) {
20166                 delete this.elementCache[i];
20167             }
20168
20169             this.elementCache = {};
20170             this.ids = {};
20171         },
20172
20173         /**
20174          * A cache of DOM elements
20175          * @property elementCache
20176          * @private
20177          * @static
20178          */
20179         elementCache: {},
20180
20181         /**
20182          * Get the wrapper for the DOM element specified
20183          * @method getElWrapper
20184          * @param {String} id the id of the element to get
20185          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20186          * @private
20187          * @deprecated This wrapper isn't that useful
20188          * @static
20189          */
20190         getElWrapper: function(id) {
20191             var oWrapper = this.elementCache[id];
20192             if (!oWrapper || !oWrapper.el) {
20193                 oWrapper = this.elementCache[id] =
20194                     new this.ElementWrapper(Roo.getDom(id));
20195             }
20196             return oWrapper;
20197         },
20198
20199         /**
20200          * Returns the actual DOM element
20201          * @method getElement
20202          * @param {String} id the id of the elment to get
20203          * @return {Object} The element
20204          * @deprecated use Roo.getDom instead
20205          * @static
20206          */
20207         getElement: function(id) {
20208             return Roo.getDom(id);
20209         },
20210
20211         /**
20212          * Returns the style property for the DOM element (i.e.,
20213          * document.getElById(id).style)
20214          * @method getCss
20215          * @param {String} id the id of the elment to get
20216          * @return {Object} The style property of the element
20217          * @deprecated use Roo.getDom instead
20218          * @static
20219          */
20220         getCss: function(id) {
20221             var el = Roo.getDom(id);
20222             return (el) ? el.style : null;
20223         },
20224
20225         /**
20226          * Inner class for cached elements
20227          * @class DragDropMgr.ElementWrapper
20228          * @for DragDropMgr
20229          * @private
20230          * @deprecated
20231          */
20232         ElementWrapper: function(el) {
20233                 /**
20234                  * The element
20235                  * @property el
20236                  */
20237                 this.el = el || null;
20238                 /**
20239                  * The element id
20240                  * @property id
20241                  */
20242                 this.id = this.el && el.id;
20243                 /**
20244                  * A reference to the style property
20245                  * @property css
20246                  */
20247                 this.css = this.el && el.style;
20248             },
20249
20250         /**
20251          * Returns the X position of an html element
20252          * @method getPosX
20253          * @param el the element for which to get the position
20254          * @return {int} the X coordinate
20255          * @for DragDropMgr
20256          * @deprecated use Roo.lib.Dom.getX instead
20257          * @static
20258          */
20259         getPosX: function(el) {
20260             return Roo.lib.Dom.getX(el);
20261         },
20262
20263         /**
20264          * Returns the Y position of an html element
20265          * @method getPosY
20266          * @param el the element for which to get the position
20267          * @return {int} the Y coordinate
20268          * @deprecated use Roo.lib.Dom.getY instead
20269          * @static
20270          */
20271         getPosY: function(el) {
20272             return Roo.lib.Dom.getY(el);
20273         },
20274
20275         /**
20276          * Swap two nodes.  In IE, we use the native method, for others we
20277          * emulate the IE behavior
20278          * @method swapNode
20279          * @param n1 the first node to swap
20280          * @param n2 the other node to swap
20281          * @static
20282          */
20283         swapNode: function(n1, n2) {
20284             if (n1.swapNode) {
20285                 n1.swapNode(n2);
20286             } else {
20287                 var p = n2.parentNode;
20288                 var s = n2.nextSibling;
20289
20290                 if (s == n1) {
20291                     p.insertBefore(n1, n2);
20292                 } else if (n2 == n1.nextSibling) {
20293                     p.insertBefore(n2, n1);
20294                 } else {
20295                     n1.parentNode.replaceChild(n2, n1);
20296                     p.insertBefore(n1, s);
20297                 }
20298             }
20299         },
20300
20301         /**
20302          * Returns the current scroll position
20303          * @method getScroll
20304          * @private
20305          * @static
20306          */
20307         getScroll: function () {
20308             var t, l, dde=document.documentElement, db=document.body;
20309             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20310                 t = dde.scrollTop;
20311                 l = dde.scrollLeft;
20312             } else if (db) {
20313                 t = db.scrollTop;
20314                 l = db.scrollLeft;
20315             } else {
20316
20317             }
20318             return { top: t, left: l };
20319         },
20320
20321         /**
20322          * Returns the specified element style property
20323          * @method getStyle
20324          * @param {HTMLElement} el          the element
20325          * @param {string}      styleProp   the style property
20326          * @return {string} The value of the style property
20327          * @deprecated use Roo.lib.Dom.getStyle
20328          * @static
20329          */
20330         getStyle: function(el, styleProp) {
20331             return Roo.fly(el).getStyle(styleProp);
20332         },
20333
20334         /**
20335          * Gets the scrollTop
20336          * @method getScrollTop
20337          * @return {int} the document's scrollTop
20338          * @static
20339          */
20340         getScrollTop: function () { return this.getScroll().top; },
20341
20342         /**
20343          * Gets the scrollLeft
20344          * @method getScrollLeft
20345          * @return {int} the document's scrollTop
20346          * @static
20347          */
20348         getScrollLeft: function () { return this.getScroll().left; },
20349
20350         /**
20351          * Sets the x/y position of an element to the location of the
20352          * target element.
20353          * @method moveToEl
20354          * @param {HTMLElement} moveEl      The element to move
20355          * @param {HTMLElement} targetEl    The position reference element
20356          * @static
20357          */
20358         moveToEl: function (moveEl, targetEl) {
20359             var aCoord = Roo.lib.Dom.getXY(targetEl);
20360             Roo.lib.Dom.setXY(moveEl, aCoord);
20361         },
20362
20363         /**
20364          * Numeric array sort function
20365          * @method numericSort
20366          * @static
20367          */
20368         numericSort: function(a, b) { return (a - b); },
20369
20370         /**
20371          * Internal counter
20372          * @property _timeoutCount
20373          * @private
20374          * @static
20375          */
20376         _timeoutCount: 0,
20377
20378         /**
20379          * Trying to make the load order less important.  Without this we get
20380          * an error if this file is loaded before the Event Utility.
20381          * @method _addListeners
20382          * @private
20383          * @static
20384          */
20385         _addListeners: function() {
20386             var DDM = Roo.dd.DDM;
20387             if ( Roo.lib.Event && document ) {
20388                 DDM._onLoad();
20389             } else {
20390                 if (DDM._timeoutCount > 2000) {
20391                 } else {
20392                     setTimeout(DDM._addListeners, 10);
20393                     if (document && document.body) {
20394                         DDM._timeoutCount += 1;
20395                     }
20396                 }
20397             }
20398         },
20399
20400         /**
20401          * Recursively searches the immediate parent and all child nodes for
20402          * the handle element in order to determine wheter or not it was
20403          * clicked.
20404          * @method handleWasClicked
20405          * @param node the html element to inspect
20406          * @static
20407          */
20408         handleWasClicked: function(node, id) {
20409             if (this.isHandle(id, node.id)) {
20410                 return true;
20411             } else {
20412                 // check to see if this is a text node child of the one we want
20413                 var p = node.parentNode;
20414
20415                 while (p) {
20416                     if (this.isHandle(id, p.id)) {
20417                         return true;
20418                     } else {
20419                         p = p.parentNode;
20420                     }
20421                 }
20422             }
20423
20424             return false;
20425         }
20426
20427     };
20428
20429 }();
20430
20431 // shorter alias, save a few bytes
20432 Roo.dd.DDM = Roo.dd.DragDropMgr;
20433 Roo.dd.DDM._addListeners();
20434
20435 }/*
20436  * Based on:
20437  * Ext JS Library 1.1.1
20438  * Copyright(c) 2006-2007, Ext JS, LLC.
20439  *
20440  * Originally Released Under LGPL - original licence link has changed is not relivant.
20441  *
20442  * Fork - LGPL
20443  * <script type="text/javascript">
20444  */
20445
20446 /**
20447  * @class Roo.dd.DD
20448  * A DragDrop implementation where the linked element follows the
20449  * mouse cursor during a drag.
20450  * @extends Roo.dd.DragDrop
20451  * @constructor
20452  * @param {String} id the id of the linked element
20453  * @param {String} sGroup the group of related DragDrop items
20454  * @param {object} config an object containing configurable attributes
20455  *                Valid properties for DD:
20456  *                    scroll
20457  */
20458 Roo.dd.DD = function(id, sGroup, config) {
20459     if (id) {
20460         this.init(id, sGroup, config);
20461     }
20462 };
20463
20464 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20465
20466     /**
20467      * When set to true, the utility automatically tries to scroll the browser
20468      * window wehn a drag and drop element is dragged near the viewport boundary.
20469      * Defaults to true.
20470      * @property scroll
20471      * @type boolean
20472      */
20473     scroll: true,
20474
20475     /**
20476      * Sets the pointer offset to the distance between the linked element's top
20477      * left corner and the location the element was clicked
20478      * @method autoOffset
20479      * @param {int} iPageX the X coordinate of the click
20480      * @param {int} iPageY the Y coordinate of the click
20481      */
20482     autoOffset: function(iPageX, iPageY) {
20483         var x = iPageX - this.startPageX;
20484         var y = iPageY - this.startPageY;
20485         this.setDelta(x, y);
20486     },
20487
20488     /**
20489      * Sets the pointer offset.  You can call this directly to force the
20490      * offset to be in a particular location (e.g., pass in 0,0 to set it
20491      * to the center of the object)
20492      * @method setDelta
20493      * @param {int} iDeltaX the distance from the left
20494      * @param {int} iDeltaY the distance from the top
20495      */
20496     setDelta: function(iDeltaX, iDeltaY) {
20497         this.deltaX = iDeltaX;
20498         this.deltaY = iDeltaY;
20499     },
20500
20501     /**
20502      * Sets the drag element to the location of the mousedown or click event,
20503      * maintaining the cursor location relative to the location on the element
20504      * that was clicked.  Override this if you want to place the element in a
20505      * location other than where the cursor is.
20506      * @method setDragElPos
20507      * @param {int} iPageX the X coordinate of the mousedown or drag event
20508      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20509      */
20510     setDragElPos: function(iPageX, iPageY) {
20511         // the first time we do this, we are going to check to make sure
20512         // the element has css positioning
20513
20514         var el = this.getDragEl();
20515         this.alignElWithMouse(el, iPageX, iPageY);
20516     },
20517
20518     /**
20519      * Sets the element to the location of the mousedown or click event,
20520      * maintaining the cursor location relative to the location on the element
20521      * that was clicked.  Override this if you want to place the element in a
20522      * location other than where the cursor is.
20523      * @method alignElWithMouse
20524      * @param {HTMLElement} el the element to move
20525      * @param {int} iPageX the X coordinate of the mousedown or drag event
20526      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20527      */
20528     alignElWithMouse: function(el, iPageX, iPageY) {
20529         var oCoord = this.getTargetCoord(iPageX, iPageY);
20530         var fly = el.dom ? el : Roo.fly(el);
20531         if (!this.deltaSetXY) {
20532             var aCoord = [oCoord.x, oCoord.y];
20533             fly.setXY(aCoord);
20534             var newLeft = fly.getLeft(true);
20535             var newTop  = fly.getTop(true);
20536             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20537         } else {
20538             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20539         }
20540
20541         this.cachePosition(oCoord.x, oCoord.y);
20542         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20543         return oCoord;
20544     },
20545
20546     /**
20547      * Saves the most recent position so that we can reset the constraints and
20548      * tick marks on-demand.  We need to know this so that we can calculate the
20549      * number of pixels the element is offset from its original position.
20550      * @method cachePosition
20551      * @param iPageX the current x position (optional, this just makes it so we
20552      * don't have to look it up again)
20553      * @param iPageY the current y position (optional, this just makes it so we
20554      * don't have to look it up again)
20555      */
20556     cachePosition: function(iPageX, iPageY) {
20557         if (iPageX) {
20558             this.lastPageX = iPageX;
20559             this.lastPageY = iPageY;
20560         } else {
20561             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20562             this.lastPageX = aCoord[0];
20563             this.lastPageY = aCoord[1];
20564         }
20565     },
20566
20567     /**
20568      * Auto-scroll the window if the dragged object has been moved beyond the
20569      * visible window boundary.
20570      * @method autoScroll
20571      * @param {int} x the drag element's x position
20572      * @param {int} y the drag element's y position
20573      * @param {int} h the height of the drag element
20574      * @param {int} w the width of the drag element
20575      * @private
20576      */
20577     autoScroll: function(x, y, h, w) {
20578
20579         if (this.scroll) {
20580             // The client height
20581             var clientH = Roo.lib.Dom.getViewWidth();
20582
20583             // The client width
20584             var clientW = Roo.lib.Dom.getViewHeight();
20585
20586             // The amt scrolled down
20587             var st = this.DDM.getScrollTop();
20588
20589             // The amt scrolled right
20590             var sl = this.DDM.getScrollLeft();
20591
20592             // Location of the bottom of the element
20593             var bot = h + y;
20594
20595             // Location of the right of the element
20596             var right = w + x;
20597
20598             // The distance from the cursor to the bottom of the visible area,
20599             // adjusted so that we don't scroll if the cursor is beyond the
20600             // element drag constraints
20601             var toBot = (clientH + st - y - this.deltaY);
20602
20603             // The distance from the cursor to the right of the visible area
20604             var toRight = (clientW + sl - x - this.deltaX);
20605
20606
20607             // How close to the edge the cursor must be before we scroll
20608             // var thresh = (document.all) ? 100 : 40;
20609             var thresh = 40;
20610
20611             // How many pixels to scroll per autoscroll op.  This helps to reduce
20612             // clunky scrolling. IE is more sensitive about this ... it needs this
20613             // value to be higher.
20614             var scrAmt = (document.all) ? 80 : 30;
20615
20616             // Scroll down if we are near the bottom of the visible page and the
20617             // obj extends below the crease
20618             if ( bot > clientH && toBot < thresh ) {
20619                 window.scrollTo(sl, st + scrAmt);
20620             }
20621
20622             // Scroll up if the window is scrolled down and the top of the object
20623             // goes above the top border
20624             if ( y < st && st > 0 && y - st < thresh ) {
20625                 window.scrollTo(sl, st - scrAmt);
20626             }
20627
20628             // Scroll right if the obj is beyond the right border and the cursor is
20629             // near the border.
20630             if ( right > clientW && toRight < thresh ) {
20631                 window.scrollTo(sl + scrAmt, st);
20632             }
20633
20634             // Scroll left if the window has been scrolled to the right and the obj
20635             // extends past the left border
20636             if ( x < sl && sl > 0 && x - sl < thresh ) {
20637                 window.scrollTo(sl - scrAmt, st);
20638             }
20639         }
20640     },
20641
20642     /**
20643      * Finds the location the element should be placed if we want to move
20644      * it to where the mouse location less the click offset would place us.
20645      * @method getTargetCoord
20646      * @param {int} iPageX the X coordinate of the click
20647      * @param {int} iPageY the Y coordinate of the click
20648      * @return an object that contains the coordinates (Object.x and Object.y)
20649      * @private
20650      */
20651     getTargetCoord: function(iPageX, iPageY) {
20652
20653
20654         var x = iPageX - this.deltaX;
20655         var y = iPageY - this.deltaY;
20656
20657         if (this.constrainX) {
20658             if (x < this.minX) { x = this.minX; }
20659             if (x > this.maxX) { x = this.maxX; }
20660         }
20661
20662         if (this.constrainY) {
20663             if (y < this.minY) { y = this.minY; }
20664             if (y > this.maxY) { y = this.maxY; }
20665         }
20666
20667         x = this.getTick(x, this.xTicks);
20668         y = this.getTick(y, this.yTicks);
20669
20670
20671         return {x:x, y:y};
20672     },
20673
20674     /*
20675      * Sets up config options specific to this class. Overrides
20676      * Roo.dd.DragDrop, but all versions of this method through the
20677      * inheritance chain are called
20678      */
20679     applyConfig: function() {
20680         Roo.dd.DD.superclass.applyConfig.call(this);
20681         this.scroll = (this.config.scroll !== false);
20682     },
20683
20684     /*
20685      * Event that fires prior to the onMouseDown event.  Overrides
20686      * Roo.dd.DragDrop.
20687      */
20688     b4MouseDown: function(e) {
20689         // this.resetConstraints();
20690         this.autoOffset(e.getPageX(),
20691                             e.getPageY());
20692     },
20693
20694     /*
20695      * Event that fires prior to the onDrag event.  Overrides
20696      * Roo.dd.DragDrop.
20697      */
20698     b4Drag: function(e) {
20699         this.setDragElPos(e.getPageX(),
20700                             e.getPageY());
20701     },
20702
20703     toString: function() {
20704         return ("DD " + this.id);
20705     }
20706
20707     //////////////////////////////////////////////////////////////////////////
20708     // Debugging ygDragDrop events that can be overridden
20709     //////////////////////////////////////////////////////////////////////////
20710     /*
20711     startDrag: function(x, y) {
20712     },
20713
20714     onDrag: function(e) {
20715     },
20716
20717     onDragEnter: function(e, id) {
20718     },
20719
20720     onDragOver: function(e, id) {
20721     },
20722
20723     onDragOut: function(e, id) {
20724     },
20725
20726     onDragDrop: function(e, id) {
20727     },
20728
20729     endDrag: function(e) {
20730     }
20731
20732     */
20733
20734 });/*
20735  * Based on:
20736  * Ext JS Library 1.1.1
20737  * Copyright(c) 2006-2007, Ext JS, LLC.
20738  *
20739  * Originally Released Under LGPL - original licence link has changed is not relivant.
20740  *
20741  * Fork - LGPL
20742  * <script type="text/javascript">
20743  */
20744
20745 /**
20746  * @class Roo.dd.DDProxy
20747  * A DragDrop implementation that inserts an empty, bordered div into
20748  * the document that follows the cursor during drag operations.  At the time of
20749  * the click, the frame div is resized to the dimensions of the linked html
20750  * element, and moved to the exact location of the linked element.
20751  *
20752  * References to the "frame" element refer to the single proxy element that
20753  * was created to be dragged in place of all DDProxy elements on the
20754  * page.
20755  *
20756  * @extends Roo.dd.DD
20757  * @constructor
20758  * @param {String} id the id of the linked html element
20759  * @param {String} sGroup the group of related DragDrop objects
20760  * @param {object} config an object containing configurable attributes
20761  *                Valid properties for DDProxy in addition to those in DragDrop:
20762  *                   resizeFrame, centerFrame, dragElId
20763  */
20764 Roo.dd.DDProxy = function(id, sGroup, config) {
20765     if (id) {
20766         this.init(id, sGroup, config);
20767         this.initFrame();
20768     }
20769 };
20770
20771 /**
20772  * The default drag frame div id
20773  * @property Roo.dd.DDProxy.dragElId
20774  * @type String
20775  * @static
20776  */
20777 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20778
20779 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20780
20781     /**
20782      * By default we resize the drag frame to be the same size as the element
20783      * we want to drag (this is to get the frame effect).  We can turn it off
20784      * if we want a different behavior.
20785      * @property resizeFrame
20786      * @type boolean
20787      */
20788     resizeFrame: true,
20789
20790     /**
20791      * By default the frame is positioned exactly where the drag element is, so
20792      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20793      * you do not have constraints on the obj is to have the drag frame centered
20794      * around the cursor.  Set centerFrame to true for this effect.
20795      * @property centerFrame
20796      * @type boolean
20797      */
20798     centerFrame: false,
20799
20800     /**
20801      * Creates the proxy element if it does not yet exist
20802      * @method createFrame
20803      */
20804     createFrame: function() {
20805         var self = this;
20806         var body = document.body;
20807
20808         if (!body || !body.firstChild) {
20809             setTimeout( function() { self.createFrame(); }, 50 );
20810             return;
20811         }
20812
20813         var div = this.getDragEl();
20814
20815         if (!div) {
20816             div    = document.createElement("div");
20817             div.id = this.dragElId;
20818             var s  = div.style;
20819
20820             s.position   = "absolute";
20821             s.visibility = "hidden";
20822             s.cursor     = "move";
20823             s.border     = "2px solid #aaa";
20824             s.zIndex     = 999;
20825
20826             // appendChild can blow up IE if invoked prior to the window load event
20827             // while rendering a table.  It is possible there are other scenarios
20828             // that would cause this to happen as well.
20829             body.insertBefore(div, body.firstChild);
20830         }
20831     },
20832
20833     /**
20834      * Initialization for the drag frame element.  Must be called in the
20835      * constructor of all subclasses
20836      * @method initFrame
20837      */
20838     initFrame: function() {
20839         this.createFrame();
20840     },
20841
20842     applyConfig: function() {
20843         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20844
20845         this.resizeFrame = (this.config.resizeFrame !== false);
20846         this.centerFrame = (this.config.centerFrame);
20847         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20848     },
20849
20850     /**
20851      * Resizes the drag frame to the dimensions of the clicked object, positions
20852      * it over the object, and finally displays it
20853      * @method showFrame
20854      * @param {int} iPageX X click position
20855      * @param {int} iPageY Y click position
20856      * @private
20857      */
20858     showFrame: function(iPageX, iPageY) {
20859         var el = this.getEl();
20860         var dragEl = this.getDragEl();
20861         var s = dragEl.style;
20862
20863         this._resizeProxy();
20864
20865         if (this.centerFrame) {
20866             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20867                            Math.round(parseInt(s.height, 10)/2) );
20868         }
20869
20870         this.setDragElPos(iPageX, iPageY);
20871
20872         Roo.fly(dragEl).show();
20873     },
20874
20875     /**
20876      * The proxy is automatically resized to the dimensions of the linked
20877      * element when a drag is initiated, unless resizeFrame is set to false
20878      * @method _resizeProxy
20879      * @private
20880      */
20881     _resizeProxy: function() {
20882         if (this.resizeFrame) {
20883             var el = this.getEl();
20884             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20885         }
20886     },
20887
20888     // overrides Roo.dd.DragDrop
20889     b4MouseDown: function(e) {
20890         var x = e.getPageX();
20891         var y = e.getPageY();
20892         this.autoOffset(x, y);
20893         this.setDragElPos(x, y);
20894     },
20895
20896     // overrides Roo.dd.DragDrop
20897     b4StartDrag: function(x, y) {
20898         // show the drag frame
20899         this.showFrame(x, y);
20900     },
20901
20902     // overrides Roo.dd.DragDrop
20903     b4EndDrag: function(e) {
20904         Roo.fly(this.getDragEl()).hide();
20905     },
20906
20907     // overrides Roo.dd.DragDrop
20908     // By default we try to move the element to the last location of the frame.
20909     // This is so that the default behavior mirrors that of Roo.dd.DD.
20910     endDrag: function(e) {
20911
20912         var lel = this.getEl();
20913         var del = this.getDragEl();
20914
20915         // Show the drag frame briefly so we can get its position
20916         del.style.visibility = "";
20917
20918         this.beforeMove();
20919         // Hide the linked element before the move to get around a Safari
20920         // rendering bug.
20921         lel.style.visibility = "hidden";
20922         Roo.dd.DDM.moveToEl(lel, del);
20923         del.style.visibility = "hidden";
20924         lel.style.visibility = "";
20925
20926         this.afterDrag();
20927     },
20928
20929     beforeMove : function(){
20930
20931     },
20932
20933     afterDrag : function(){
20934
20935     },
20936
20937     toString: function() {
20938         return ("DDProxy " + this.id);
20939     }
20940
20941 });
20942 /*
20943  * Based on:
20944  * Ext JS Library 1.1.1
20945  * Copyright(c) 2006-2007, Ext JS, LLC.
20946  *
20947  * Originally Released Under LGPL - original licence link has changed is not relivant.
20948  *
20949  * Fork - LGPL
20950  * <script type="text/javascript">
20951  */
20952
20953  /**
20954  * @class Roo.dd.DDTarget
20955  * A DragDrop implementation that does not move, but can be a drop
20956  * target.  You would get the same result by simply omitting implementation
20957  * for the event callbacks, but this way we reduce the processing cost of the
20958  * event listener and the callbacks.
20959  * @extends Roo.dd.DragDrop
20960  * @constructor
20961  * @param {String} id the id of the element that is a drop target
20962  * @param {String} sGroup the group of related DragDrop objects
20963  * @param {object} config an object containing configurable attributes
20964  *                 Valid properties for DDTarget in addition to those in
20965  *                 DragDrop:
20966  *                    none
20967  */
20968 Roo.dd.DDTarget = function(id, sGroup, config) {
20969     if (id) {
20970         this.initTarget(id, sGroup, config);
20971     }
20972     if (config.listeners || config.events) { 
20973        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20974             listeners : config.listeners || {}, 
20975             events : config.events || {} 
20976         });    
20977     }
20978 };
20979
20980 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20981 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20982     toString: function() {
20983         return ("DDTarget " + this.id);
20984     }
20985 });
20986 /*
20987  * Based on:
20988  * Ext JS Library 1.1.1
20989  * Copyright(c) 2006-2007, Ext JS, LLC.
20990  *
20991  * Originally Released Under LGPL - original licence link has changed is not relivant.
20992  *
20993  * Fork - LGPL
20994  * <script type="text/javascript">
20995  */
20996  
20997
20998 /**
20999  * @class Roo.dd.ScrollManager
21000  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21001  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21002  * @singleton
21003  */
21004 Roo.dd.ScrollManager = function(){
21005     var ddm = Roo.dd.DragDropMgr;
21006     var els = {};
21007     var dragEl = null;
21008     var proc = {};
21009     
21010     
21011     
21012     var onStop = function(e){
21013         dragEl = null;
21014         clearProc();
21015     };
21016     
21017     var triggerRefresh = function(){
21018         if(ddm.dragCurrent){
21019              ddm.refreshCache(ddm.dragCurrent.groups);
21020         }
21021     };
21022     
21023     var doScroll = function(){
21024         if(ddm.dragCurrent){
21025             var dds = Roo.dd.ScrollManager;
21026             if(!dds.animate){
21027                 if(proc.el.scroll(proc.dir, dds.increment)){
21028                     triggerRefresh();
21029                 }
21030             }else{
21031                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21032             }
21033         }
21034     };
21035     
21036     var clearProc = function(){
21037         if(proc.id){
21038             clearInterval(proc.id);
21039         }
21040         proc.id = 0;
21041         proc.el = null;
21042         proc.dir = "";
21043     };
21044     
21045     var startProc = function(el, dir){
21046          Roo.log('scroll startproc');
21047         clearProc();
21048         proc.el = el;
21049         proc.dir = dir;
21050         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21051     };
21052     
21053     var onFire = function(e, isDrop){
21054        
21055         if(isDrop || !ddm.dragCurrent){ return; }
21056         var dds = Roo.dd.ScrollManager;
21057         if(!dragEl || dragEl != ddm.dragCurrent){
21058             dragEl = ddm.dragCurrent;
21059             // refresh regions on drag start
21060             dds.refreshCache();
21061         }
21062         
21063         var xy = Roo.lib.Event.getXY(e);
21064         var pt = new Roo.lib.Point(xy[0], xy[1]);
21065         for(var id in els){
21066             var el = els[id], r = el._region;
21067             if(r && r.contains(pt) && el.isScrollable()){
21068                 if(r.bottom - pt.y <= dds.thresh){
21069                     if(proc.el != el){
21070                         startProc(el, "down");
21071                     }
21072                     return;
21073                 }else if(r.right - pt.x <= dds.thresh){
21074                     if(proc.el != el){
21075                         startProc(el, "left");
21076                     }
21077                     return;
21078                 }else if(pt.y - r.top <= dds.thresh){
21079                     if(proc.el != el){
21080                         startProc(el, "up");
21081                     }
21082                     return;
21083                 }else if(pt.x - r.left <= dds.thresh){
21084                     if(proc.el != el){
21085                         startProc(el, "right");
21086                     }
21087                     return;
21088                 }
21089             }
21090         }
21091         clearProc();
21092     };
21093     
21094     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21095     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21096     
21097     return {
21098         /**
21099          * Registers new overflow element(s) to auto scroll
21100          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21101          */
21102         register : function(el){
21103             if(el instanceof Array){
21104                 for(var i = 0, len = el.length; i < len; i++) {
21105                         this.register(el[i]);
21106                 }
21107             }else{
21108                 el = Roo.get(el);
21109                 els[el.id] = el;
21110             }
21111             Roo.dd.ScrollManager.els = els;
21112         },
21113         
21114         /**
21115          * Unregisters overflow element(s) so they are no longer scrolled
21116          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21117          */
21118         unregister : function(el){
21119             if(el instanceof Array){
21120                 for(var i = 0, len = el.length; i < len; i++) {
21121                         this.unregister(el[i]);
21122                 }
21123             }else{
21124                 el = Roo.get(el);
21125                 delete els[el.id];
21126             }
21127         },
21128         
21129         /**
21130          * The number of pixels from the edge of a container the pointer needs to be to 
21131          * trigger scrolling (defaults to 25)
21132          * @type Number
21133          */
21134         thresh : 25,
21135         
21136         /**
21137          * The number of pixels to scroll in each scroll increment (defaults to 50)
21138          * @type Number
21139          */
21140         increment : 100,
21141         
21142         /**
21143          * The frequency of scrolls in milliseconds (defaults to 500)
21144          * @type Number
21145          */
21146         frequency : 500,
21147         
21148         /**
21149          * True to animate the scroll (defaults to true)
21150          * @type Boolean
21151          */
21152         animate: true,
21153         
21154         /**
21155          * The animation duration in seconds - 
21156          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21157          * @type Number
21158          */
21159         animDuration: .4,
21160         
21161         /**
21162          * Manually trigger a cache refresh.
21163          */
21164         refreshCache : function(){
21165             for(var id in els){
21166                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21167                     els[id]._region = els[id].getRegion();
21168                 }
21169             }
21170         }
21171     };
21172 }();/*
21173  * Based on:
21174  * Ext JS Library 1.1.1
21175  * Copyright(c) 2006-2007, Ext JS, LLC.
21176  *
21177  * Originally Released Under LGPL - original licence link has changed is not relivant.
21178  *
21179  * Fork - LGPL
21180  * <script type="text/javascript">
21181  */
21182  
21183
21184 /**
21185  * @class Roo.dd.Registry
21186  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21187  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21188  * @singleton
21189  */
21190 Roo.dd.Registry = function(){
21191     var elements = {}; 
21192     var handles = {}; 
21193     var autoIdSeed = 0;
21194
21195     var getId = function(el, autogen){
21196         if(typeof el == "string"){
21197             return el;
21198         }
21199         var id = el.id;
21200         if(!id && autogen !== false){
21201             id = "roodd-" + (++autoIdSeed);
21202             el.id = id;
21203         }
21204         return id;
21205     };
21206     
21207     return {
21208     /**
21209      * Register a drag drop element
21210      * @param {String|HTMLElement} element The id or DOM node to register
21211      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21212      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21213      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21214      * populated in the data object (if applicable):
21215      * <pre>
21216 Value      Description<br />
21217 ---------  ------------------------------------------<br />
21218 handles    Array of DOM nodes that trigger dragging<br />
21219            for the element being registered<br />
21220 isHandle   True if the element passed in triggers<br />
21221            dragging itself, else false
21222 </pre>
21223      */
21224         register : function(el, data){
21225             data = data || {};
21226             if(typeof el == "string"){
21227                 el = document.getElementById(el);
21228             }
21229             data.ddel = el;
21230             elements[getId(el)] = data;
21231             if(data.isHandle !== false){
21232                 handles[data.ddel.id] = data;
21233             }
21234             if(data.handles){
21235                 var hs = data.handles;
21236                 for(var i = 0, len = hs.length; i < len; i++){
21237                         handles[getId(hs[i])] = data;
21238                 }
21239             }
21240         },
21241
21242     /**
21243      * Unregister a drag drop element
21244      * @param {String|HTMLElement}  element The id or DOM node to unregister
21245      */
21246         unregister : function(el){
21247             var id = getId(el, false);
21248             var data = elements[id];
21249             if(data){
21250                 delete elements[id];
21251                 if(data.handles){
21252                     var hs = data.handles;
21253                     for(var i = 0, len = hs.length; i < len; i++){
21254                         delete handles[getId(hs[i], false)];
21255                     }
21256                 }
21257             }
21258         },
21259
21260     /**
21261      * Returns the handle registered for a DOM Node by id
21262      * @param {String|HTMLElement} id The DOM node or id to look up
21263      * @return {Object} handle The custom handle data
21264      */
21265         getHandle : function(id){
21266             if(typeof id != "string"){ // must be element?
21267                 id = id.id;
21268             }
21269             return handles[id];
21270         },
21271
21272     /**
21273      * Returns the handle that is registered for the DOM node that is the target of the event
21274      * @param {Event} e The event
21275      * @return {Object} handle The custom handle data
21276      */
21277         getHandleFromEvent : function(e){
21278             var t = Roo.lib.Event.getTarget(e);
21279             return t ? handles[t.id] : null;
21280         },
21281
21282     /**
21283      * Returns a custom data object that is registered for a DOM node by id
21284      * @param {String|HTMLElement} id The DOM node or id to look up
21285      * @return {Object} data The custom data
21286      */
21287         getTarget : function(id){
21288             if(typeof id != "string"){ // must be element?
21289                 id = id.id;
21290             }
21291             return elements[id];
21292         },
21293
21294     /**
21295      * Returns a custom data object that is registered for the DOM node that is the target of the event
21296      * @param {Event} e The event
21297      * @return {Object} data The custom data
21298      */
21299         getTargetFromEvent : function(e){
21300             var t = Roo.lib.Event.getTarget(e);
21301             return t ? elements[t.id] || handles[t.id] : null;
21302         }
21303     };
21304 }();/*
21305  * Based on:
21306  * Ext JS Library 1.1.1
21307  * Copyright(c) 2006-2007, Ext JS, LLC.
21308  *
21309  * Originally Released Under LGPL - original licence link has changed is not relivant.
21310  *
21311  * Fork - LGPL
21312  * <script type="text/javascript">
21313  */
21314  
21315
21316 /**
21317  * @class Roo.dd.StatusProxy
21318  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21319  * default drag proxy used by all Roo.dd components.
21320  * @constructor
21321  * @param {Object} config
21322  */
21323 Roo.dd.StatusProxy = function(config){
21324     Roo.apply(this, config);
21325     this.id = this.id || Roo.id();
21326     this.el = new Roo.Layer({
21327         dh: {
21328             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21329                 {tag: "div", cls: "x-dd-drop-icon"},
21330                 {tag: "div", cls: "x-dd-drag-ghost"}
21331             ]
21332         }, 
21333         shadow: !config || config.shadow !== false
21334     });
21335     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21336     this.dropStatus = this.dropNotAllowed;
21337 };
21338
21339 Roo.dd.StatusProxy.prototype = {
21340     /**
21341      * @cfg {String} dropAllowed
21342      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21343      */
21344     dropAllowed : "x-dd-drop-ok",
21345     /**
21346      * @cfg {String} dropNotAllowed
21347      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21348      */
21349     dropNotAllowed : "x-dd-drop-nodrop",
21350
21351     /**
21352      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21353      * over the current target element.
21354      * @param {String} cssClass The css class for the new drop status indicator image
21355      */
21356     setStatus : function(cssClass){
21357         cssClass = cssClass || this.dropNotAllowed;
21358         if(this.dropStatus != cssClass){
21359             this.el.replaceClass(this.dropStatus, cssClass);
21360             this.dropStatus = cssClass;
21361         }
21362     },
21363
21364     /**
21365      * Resets the status indicator to the default dropNotAllowed value
21366      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21367      */
21368     reset : function(clearGhost){
21369         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21370         this.dropStatus = this.dropNotAllowed;
21371         if(clearGhost){
21372             this.ghost.update("");
21373         }
21374     },
21375
21376     /**
21377      * Updates the contents of the ghost element
21378      * @param {String} html The html that will replace the current innerHTML of the ghost element
21379      */
21380     update : function(html){
21381         if(typeof html == "string"){
21382             this.ghost.update(html);
21383         }else{
21384             this.ghost.update("");
21385             html.style.margin = "0";
21386             this.ghost.dom.appendChild(html);
21387         }
21388         // ensure float = none set?? cant remember why though.
21389         var el = this.ghost.dom.firstChild;
21390                 if(el){
21391                         Roo.fly(el).setStyle('float', 'none');
21392                 }
21393     },
21394     
21395     /**
21396      * Returns the underlying proxy {@link Roo.Layer}
21397      * @return {Roo.Layer} el
21398     */
21399     getEl : function(){
21400         return this.el;
21401     },
21402
21403     /**
21404      * Returns the ghost element
21405      * @return {Roo.Element} el
21406      */
21407     getGhost : function(){
21408         return this.ghost;
21409     },
21410
21411     /**
21412      * Hides the proxy
21413      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21414      */
21415     hide : function(clear){
21416         this.el.hide();
21417         if(clear){
21418             this.reset(true);
21419         }
21420     },
21421
21422     /**
21423      * Stops the repair animation if it's currently running
21424      */
21425     stop : function(){
21426         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21427             this.anim.stop();
21428         }
21429     },
21430
21431     /**
21432      * Displays this proxy
21433      */
21434     show : function(){
21435         this.el.show();
21436     },
21437
21438     /**
21439      * Force the Layer to sync its shadow and shim positions to the element
21440      */
21441     sync : function(){
21442         this.el.sync();
21443     },
21444
21445     /**
21446      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21447      * invalid drop operation by the item being dragged.
21448      * @param {Array} xy The XY position of the element ([x, y])
21449      * @param {Function} callback The function to call after the repair is complete
21450      * @param {Object} scope The scope in which to execute the callback
21451      */
21452     repair : function(xy, callback, scope){
21453         this.callback = callback;
21454         this.scope = scope;
21455         if(xy && this.animRepair !== false){
21456             this.el.addClass("x-dd-drag-repair");
21457             this.el.hideUnders(true);
21458             this.anim = this.el.shift({
21459                 duration: this.repairDuration || .5,
21460                 easing: 'easeOut',
21461                 xy: xy,
21462                 stopFx: true,
21463                 callback: this.afterRepair,
21464                 scope: this
21465             });
21466         }else{
21467             this.afterRepair();
21468         }
21469     },
21470
21471     // private
21472     afterRepair : function(){
21473         this.hide(true);
21474         if(typeof this.callback == "function"){
21475             this.callback.call(this.scope || this);
21476         }
21477         this.callback = null;
21478         this.scope = null;
21479     }
21480 };/*
21481  * Based on:
21482  * Ext JS Library 1.1.1
21483  * Copyright(c) 2006-2007, Ext JS, LLC.
21484  *
21485  * Originally Released Under LGPL - original licence link has changed is not relivant.
21486  *
21487  * Fork - LGPL
21488  * <script type="text/javascript">
21489  */
21490
21491 /**
21492  * @class Roo.dd.DragSource
21493  * @extends Roo.dd.DDProxy
21494  * A simple class that provides the basic implementation needed to make any element draggable.
21495  * @constructor
21496  * @param {String/HTMLElement/Element} el The container element
21497  * @param {Object} config
21498  */
21499 Roo.dd.DragSource = function(el, config){
21500     this.el = Roo.get(el);
21501     this.dragData = {};
21502     
21503     Roo.apply(this, config);
21504     
21505     if(!this.proxy){
21506         this.proxy = new Roo.dd.StatusProxy();
21507     }
21508
21509     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21510           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21511     
21512     this.dragging = false;
21513 };
21514
21515 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21516     /**
21517      * @cfg {String} dropAllowed
21518      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21519      */
21520     dropAllowed : "x-dd-drop-ok",
21521     /**
21522      * @cfg {String} dropNotAllowed
21523      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21524      */
21525     dropNotAllowed : "x-dd-drop-nodrop",
21526
21527     /**
21528      * Returns the data object associated with this drag source
21529      * @return {Object} data An object containing arbitrary data
21530      */
21531     getDragData : function(e){
21532         return this.dragData;
21533     },
21534
21535     // private
21536     onDragEnter : function(e, id){
21537         var target = Roo.dd.DragDropMgr.getDDById(id);
21538         this.cachedTarget = target;
21539         if(this.beforeDragEnter(target, e, id) !== false){
21540             if(target.isNotifyTarget){
21541                 var status = target.notifyEnter(this, e, this.dragData);
21542                 this.proxy.setStatus(status);
21543             }else{
21544                 this.proxy.setStatus(this.dropAllowed);
21545             }
21546             
21547             if(this.afterDragEnter){
21548                 /**
21549                  * An empty function by default, but provided so that you can perform a custom action
21550                  * when the dragged item enters the drop target by providing an implementation.
21551                  * @param {Roo.dd.DragDrop} target The drop target
21552                  * @param {Event} e The event object
21553                  * @param {String} id The id of the dragged element
21554                  * @method afterDragEnter
21555                  */
21556                 this.afterDragEnter(target, e, id);
21557             }
21558         }
21559     },
21560
21561     /**
21562      * An empty function by default, but provided so that you can perform a custom action
21563      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21564      * @param {Roo.dd.DragDrop} target The drop target
21565      * @param {Event} e The event object
21566      * @param {String} id The id of the dragged element
21567      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21568      */
21569     beforeDragEnter : function(target, e, id){
21570         return true;
21571     },
21572
21573     // private
21574     alignElWithMouse: function() {
21575         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21576         this.proxy.sync();
21577     },
21578
21579     // private
21580     onDragOver : function(e, id){
21581         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21582         if(this.beforeDragOver(target, e, id) !== false){
21583             if(target.isNotifyTarget){
21584                 var status = target.notifyOver(this, e, this.dragData);
21585                 this.proxy.setStatus(status);
21586             }
21587
21588             if(this.afterDragOver){
21589                 /**
21590                  * An empty function by default, but provided so that you can perform a custom action
21591                  * while the dragged item is over the drop target by providing an implementation.
21592                  * @param {Roo.dd.DragDrop} target The drop target
21593                  * @param {Event} e The event object
21594                  * @param {String} id The id of the dragged element
21595                  * @method afterDragOver
21596                  */
21597                 this.afterDragOver(target, e, id);
21598             }
21599         }
21600     },
21601
21602     /**
21603      * An empty function by default, but provided so that you can perform a custom action
21604      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21605      * @param {Roo.dd.DragDrop} target The drop target
21606      * @param {Event} e The event object
21607      * @param {String} id The id of the dragged element
21608      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21609      */
21610     beforeDragOver : function(target, e, id){
21611         return true;
21612     },
21613
21614     // private
21615     onDragOut : function(e, id){
21616         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21617         if(this.beforeDragOut(target, e, id) !== false){
21618             if(target.isNotifyTarget){
21619                 target.notifyOut(this, e, this.dragData);
21620             }
21621             this.proxy.reset();
21622             if(this.afterDragOut){
21623                 /**
21624                  * An empty function by default, but provided so that you can perform a custom action
21625                  * after the dragged item is dragged out of the target without dropping.
21626                  * @param {Roo.dd.DragDrop} target The drop target
21627                  * @param {Event} e The event object
21628                  * @param {String} id The id of the dragged element
21629                  * @method afterDragOut
21630                  */
21631                 this.afterDragOut(target, e, id);
21632             }
21633         }
21634         this.cachedTarget = null;
21635     },
21636
21637     /**
21638      * An empty function by default, but provided so that you can perform a custom action before the dragged
21639      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21640      * @param {Roo.dd.DragDrop} target The drop target
21641      * @param {Event} e The event object
21642      * @param {String} id The id of the dragged element
21643      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21644      */
21645     beforeDragOut : function(target, e, id){
21646         return true;
21647     },
21648     
21649     // private
21650     onDragDrop : function(e, id){
21651         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21652         if(this.beforeDragDrop(target, e, id) !== false){
21653             if(target.isNotifyTarget){
21654                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21655                     this.onValidDrop(target, e, id);
21656                 }else{
21657                     this.onInvalidDrop(target, e, id);
21658                 }
21659             }else{
21660                 this.onValidDrop(target, e, id);
21661             }
21662             
21663             if(this.afterDragDrop){
21664                 /**
21665                  * An empty function by default, but provided so that you can perform a custom action
21666                  * after a valid drag drop has occurred by providing an implementation.
21667                  * @param {Roo.dd.DragDrop} target The drop target
21668                  * @param {Event} e The event object
21669                  * @param {String} id The id of the dropped element
21670                  * @method afterDragDrop
21671                  */
21672                 this.afterDragDrop(target, e, id);
21673             }
21674         }
21675         delete this.cachedTarget;
21676     },
21677
21678     /**
21679      * An empty function by default, but provided so that you can perform a custom action before the dragged
21680      * item is dropped onto the target and optionally cancel the onDragDrop.
21681      * @param {Roo.dd.DragDrop} target The drop target
21682      * @param {Event} e The event object
21683      * @param {String} id The id of the dragged element
21684      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21685      */
21686     beforeDragDrop : function(target, e, id){
21687         return true;
21688     },
21689
21690     // private
21691     onValidDrop : function(target, e, id){
21692         this.hideProxy();
21693         if(this.afterValidDrop){
21694             /**
21695              * An empty function by default, but provided so that you can perform a custom action
21696              * after a valid drop has occurred by providing an implementation.
21697              * @param {Object} target The target DD 
21698              * @param {Event} e The event object
21699              * @param {String} id The id of the dropped element
21700              * @method afterInvalidDrop
21701              */
21702             this.afterValidDrop(target, e, id);
21703         }
21704     },
21705
21706     // private
21707     getRepairXY : function(e, data){
21708         return this.el.getXY();  
21709     },
21710
21711     // private
21712     onInvalidDrop : function(target, e, id){
21713         this.beforeInvalidDrop(target, e, id);
21714         if(this.cachedTarget){
21715             if(this.cachedTarget.isNotifyTarget){
21716                 this.cachedTarget.notifyOut(this, e, this.dragData);
21717             }
21718             this.cacheTarget = null;
21719         }
21720         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21721
21722         if(this.afterInvalidDrop){
21723             /**
21724              * An empty function by default, but provided so that you can perform a custom action
21725              * after an invalid drop has occurred by providing an implementation.
21726              * @param {Event} e The event object
21727              * @param {String} id The id of the dropped element
21728              * @method afterInvalidDrop
21729              */
21730             this.afterInvalidDrop(e, id);
21731         }
21732     },
21733
21734     // private
21735     afterRepair : function(){
21736         if(Roo.enableFx){
21737             this.el.highlight(this.hlColor || "c3daf9");
21738         }
21739         this.dragging = false;
21740     },
21741
21742     /**
21743      * An empty function by default, but provided so that you can perform a custom action after an invalid
21744      * drop has occurred.
21745      * @param {Roo.dd.DragDrop} target The drop target
21746      * @param {Event} e The event object
21747      * @param {String} id The id of the dragged element
21748      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21749      */
21750     beforeInvalidDrop : function(target, e, id){
21751         return true;
21752     },
21753
21754     // private
21755     handleMouseDown : function(e){
21756         if(this.dragging) {
21757             return;
21758         }
21759         var data = this.getDragData(e);
21760         if(data && this.onBeforeDrag(data, e) !== false){
21761             this.dragData = data;
21762             this.proxy.stop();
21763             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21764         } 
21765     },
21766
21767     /**
21768      * An empty function by default, but provided so that you can perform a custom action before the initial
21769      * drag event begins and optionally cancel it.
21770      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21771      * @param {Event} e The event object
21772      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21773      */
21774     onBeforeDrag : function(data, e){
21775         return true;
21776     },
21777
21778     /**
21779      * An empty function by default, but provided so that you can perform a custom action once the initial
21780      * drag event has begun.  The drag cannot be canceled from this function.
21781      * @param {Number} x The x position of the click on the dragged object
21782      * @param {Number} y The y position of the click on the dragged object
21783      */
21784     onStartDrag : Roo.emptyFn,
21785
21786     // private - YUI override
21787     startDrag : function(x, y){
21788         this.proxy.reset();
21789         this.dragging = true;
21790         this.proxy.update("");
21791         this.onInitDrag(x, y);
21792         this.proxy.show();
21793     },
21794
21795     // private
21796     onInitDrag : function(x, y){
21797         var clone = this.el.dom.cloneNode(true);
21798         clone.id = Roo.id(); // prevent duplicate ids
21799         this.proxy.update(clone);
21800         this.onStartDrag(x, y);
21801         return true;
21802     },
21803
21804     /**
21805      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21806      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21807      */
21808     getProxy : function(){
21809         return this.proxy;  
21810     },
21811
21812     /**
21813      * Hides the drag source's {@link Roo.dd.StatusProxy}
21814      */
21815     hideProxy : function(){
21816         this.proxy.hide();  
21817         this.proxy.reset(true);
21818         this.dragging = false;
21819     },
21820
21821     // private
21822     triggerCacheRefresh : function(){
21823         Roo.dd.DDM.refreshCache(this.groups);
21824     },
21825
21826     // private - override to prevent hiding
21827     b4EndDrag: function(e) {
21828     },
21829
21830     // private - override to prevent moving
21831     endDrag : function(e){
21832         this.onEndDrag(this.dragData, e);
21833     },
21834
21835     // private
21836     onEndDrag : function(data, e){
21837     },
21838     
21839     // private - pin to cursor
21840     autoOffset : function(x, y) {
21841         this.setDelta(-12, -20);
21842     }    
21843 });/*
21844  * Based on:
21845  * Ext JS Library 1.1.1
21846  * Copyright(c) 2006-2007, Ext JS, LLC.
21847  *
21848  * Originally Released Under LGPL - original licence link has changed is not relivant.
21849  *
21850  * Fork - LGPL
21851  * <script type="text/javascript">
21852  */
21853
21854
21855 /**
21856  * @class Roo.dd.DropTarget
21857  * @extends Roo.dd.DDTarget
21858  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21859  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21860  * @constructor
21861  * @param {String/HTMLElement/Element} el The container element
21862  * @param {Object} config
21863  */
21864 Roo.dd.DropTarget = function(el, config){
21865     this.el = Roo.get(el);
21866     
21867     var listeners = false; ;
21868     if (config && config.listeners) {
21869         listeners= config.listeners;
21870         delete config.listeners;
21871     }
21872     Roo.apply(this, config);
21873     
21874     if(this.containerScroll){
21875         Roo.dd.ScrollManager.register(this.el);
21876     }
21877     this.addEvents( {
21878          /**
21879          * @scope Roo.dd.DropTarget
21880          */
21881          
21882          /**
21883          * @event enter
21884          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21885          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21886          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21887          * 
21888          * IMPORTANT : it should set this.overClass and this.dropAllowed
21889          * 
21890          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21891          * @param {Event} e The event
21892          * @param {Object} data An object containing arbitrary data supplied by the drag source
21893          */
21894         "enter" : true,
21895         
21896          /**
21897          * @event over
21898          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21899          * This method will be called on every mouse movement while the drag source is over the drop target.
21900          * This default implementation simply returns the dropAllowed config value.
21901          * 
21902          * IMPORTANT : it should set this.dropAllowed
21903          * 
21904          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21905          * @param {Event} e The event
21906          * @param {Object} data An object containing arbitrary data supplied by the drag source
21907          
21908          */
21909         "over" : true,
21910         /**
21911          * @event out
21912          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21913          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21914          * overClass (if any) from the drop element.
21915          * 
21916          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21917          * @param {Event} e The event
21918          * @param {Object} data An object containing arbitrary data supplied by the drag source
21919          */
21920          "out" : true,
21921          
21922         /**
21923          * @event drop
21924          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21925          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21926          * implementation that does something to process the drop event and returns true so that the drag source's
21927          * repair action does not run.
21928          * 
21929          * IMPORTANT : it should set this.success
21930          * 
21931          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21932          * @param {Event} e The event
21933          * @param {Object} data An object containing arbitrary data supplied by the drag source
21934         */
21935          "drop" : true
21936     });
21937             
21938      
21939     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21940         this.el.dom, 
21941         this.ddGroup || this.group,
21942         {
21943             isTarget: true,
21944             listeners : listeners || {} 
21945            
21946         
21947         }
21948     );
21949
21950 };
21951
21952 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21953     /**
21954      * @cfg {String} overClass
21955      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21956      */
21957      /**
21958      * @cfg {String} ddGroup
21959      * The drag drop group to handle drop events for
21960      */
21961      
21962     /**
21963      * @cfg {String} dropAllowed
21964      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21965      */
21966     dropAllowed : "x-dd-drop-ok",
21967     /**
21968      * @cfg {String} dropNotAllowed
21969      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21970      */
21971     dropNotAllowed : "x-dd-drop-nodrop",
21972     /**
21973      * @cfg {boolean} success
21974      * set this after drop listener.. 
21975      */
21976     success : false,
21977     /**
21978      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21979      * if the drop point is valid for over/enter..
21980      */
21981     valid : false,
21982     // private
21983     isTarget : true,
21984
21985     // private
21986     isNotifyTarget : true,
21987     
21988     /**
21989      * @hide
21990      */
21991     notifyEnter : function(dd, e, data)
21992     {
21993         this.valid = true;
21994         this.fireEvent('enter', dd, e, data);
21995         if(this.overClass){
21996             this.el.addClass(this.overClass);
21997         }
21998         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21999             this.valid ? this.dropAllowed : this.dropNotAllowed
22000         );
22001     },
22002
22003     /**
22004      * @hide
22005      */
22006     notifyOver : function(dd, e, data)
22007     {
22008         this.valid = true;
22009         this.fireEvent('over', dd, e, data);
22010         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22011             this.valid ? this.dropAllowed : this.dropNotAllowed
22012         );
22013     },
22014
22015     /**
22016      * @hide
22017      */
22018     notifyOut : function(dd, e, data)
22019     {
22020         this.fireEvent('out', dd, e, data);
22021         if(this.overClass){
22022             this.el.removeClass(this.overClass);
22023         }
22024     },
22025
22026     /**
22027      * @hide
22028      */
22029     notifyDrop : function(dd, e, data)
22030     {
22031         this.success = false;
22032         this.fireEvent('drop', dd, e, data);
22033         return this.success;
22034     }
22035 });/*
22036  * Based on:
22037  * Ext JS Library 1.1.1
22038  * Copyright(c) 2006-2007, Ext JS, LLC.
22039  *
22040  * Originally Released Under LGPL - original licence link has changed is not relivant.
22041  *
22042  * Fork - LGPL
22043  * <script type="text/javascript">
22044  */
22045
22046
22047 /**
22048  * @class Roo.dd.DragZone
22049  * @extends Roo.dd.DragSource
22050  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22051  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22052  * @constructor
22053  * @param {String/HTMLElement/Element} el The container element
22054  * @param {Object} config
22055  */
22056 Roo.dd.DragZone = function(el, config){
22057     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22058     if(this.containerScroll){
22059         Roo.dd.ScrollManager.register(this.el);
22060     }
22061 };
22062
22063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22064     /**
22065      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22066      * for auto scrolling during drag operations.
22067      */
22068     /**
22069      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22070      * method after a failed drop (defaults to "c3daf9" - light blue)
22071      */
22072
22073     /**
22074      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22075      * for a valid target to drag based on the mouse down. Override this method
22076      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22077      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22078      * @param {EventObject} e The mouse down event
22079      * @return {Object} The dragData
22080      */
22081     getDragData : function(e){
22082         return Roo.dd.Registry.getHandleFromEvent(e);
22083     },
22084     
22085     /**
22086      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22087      * this.dragData.ddel
22088      * @param {Number} x The x position of the click on the dragged object
22089      * @param {Number} y The y position of the click on the dragged object
22090      * @return {Boolean} true to continue the drag, false to cancel
22091      */
22092     onInitDrag : function(x, y){
22093         this.proxy.update(this.dragData.ddel.cloneNode(true));
22094         this.onStartDrag(x, y);
22095         return true;
22096     },
22097     
22098     /**
22099      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22100      */
22101     afterRepair : function(){
22102         if(Roo.enableFx){
22103             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22104         }
22105         this.dragging = false;
22106     },
22107
22108     /**
22109      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22110      * the XY of this.dragData.ddel
22111      * @param {EventObject} e The mouse up event
22112      * @return {Array} The xy location (e.g. [100, 200])
22113      */
22114     getRepairXY : function(e){
22115         return Roo.Element.fly(this.dragData.ddel).getXY();  
22116     }
22117 });/*
22118  * Based on:
22119  * Ext JS Library 1.1.1
22120  * Copyright(c) 2006-2007, Ext JS, LLC.
22121  *
22122  * Originally Released Under LGPL - original licence link has changed is not relivant.
22123  *
22124  * Fork - LGPL
22125  * <script type="text/javascript">
22126  */
22127 /**
22128  * @class Roo.dd.DropZone
22129  * @extends Roo.dd.DropTarget
22130  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22131  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22132  * @constructor
22133  * @param {String/HTMLElement/Element} el The container element
22134  * @param {Object} config
22135  */
22136 Roo.dd.DropZone = function(el, config){
22137     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22138 };
22139
22140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22141     /**
22142      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22143      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22144      * provide your own custom lookup.
22145      * @param {Event} e The event
22146      * @return {Object} data The custom data
22147      */
22148     getTargetFromEvent : function(e){
22149         return Roo.dd.Registry.getTargetFromEvent(e);
22150     },
22151
22152     /**
22153      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22154      * that it has registered.  This method has no default implementation and should be overridden to provide
22155      * node-specific processing if necessary.
22156      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22157      * {@link #getTargetFromEvent} for this node)
22158      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22159      * @param {Event} e The event
22160      * @param {Object} data An object containing arbitrary data supplied by the drag source
22161      */
22162     onNodeEnter : function(n, dd, e, data){
22163         
22164     },
22165
22166     /**
22167      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22168      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22169      * overridden to provide the proper feedback.
22170      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22171      * {@link #getTargetFromEvent} for this node)
22172      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22173      * @param {Event} e The event
22174      * @param {Object} data An object containing arbitrary data supplied by the drag source
22175      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22176      * underlying {@link Roo.dd.StatusProxy} can be updated
22177      */
22178     onNodeOver : function(n, dd, e, data){
22179         return this.dropAllowed;
22180     },
22181
22182     /**
22183      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22184      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22185      * node-specific processing if necessary.
22186      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22187      * {@link #getTargetFromEvent} for this node)
22188      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22189      * @param {Event} e The event
22190      * @param {Object} data An object containing arbitrary data supplied by the drag source
22191      */
22192     onNodeOut : function(n, dd, e, data){
22193         
22194     },
22195
22196     /**
22197      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22198      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22199      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22200      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22201      * {@link #getTargetFromEvent} for this node)
22202      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22203      * @param {Event} e The event
22204      * @param {Object} data An object containing arbitrary data supplied by the drag source
22205      * @return {Boolean} True if the drop was valid, else false
22206      */
22207     onNodeDrop : function(n, dd, e, data){
22208         return false;
22209     },
22210
22211     /**
22212      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22213      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22214      * it should be overridden to provide the proper feedback if necessary.
22215      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22216      * @param {Event} e The event
22217      * @param {Object} data An object containing arbitrary data supplied by the drag source
22218      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22219      * underlying {@link Roo.dd.StatusProxy} can be updated
22220      */
22221     onContainerOver : function(dd, e, data){
22222         return this.dropNotAllowed;
22223     },
22224
22225     /**
22226      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22227      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22228      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22229      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
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 {Boolean} True if the drop was valid, else false
22234      */
22235     onContainerDrop : function(dd, e, data){
22236         return false;
22237     },
22238
22239     /**
22240      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22241      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22242      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22243      * you should override this method and provide a custom implementation.
22244      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22245      * @param {Event} e The event
22246      * @param {Object} data An object containing arbitrary data supplied by the drag source
22247      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22248      * underlying {@link Roo.dd.StatusProxy} can be updated
22249      */
22250     notifyEnter : function(dd, e, data){
22251         return this.dropNotAllowed;
22252     },
22253
22254     /**
22255      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22256      * This method will be called on every mouse movement while the drag source is over the drop zone.
22257      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22258      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22259      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22260      * registered node, it will call {@link #onContainerOver}.
22261      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22262      * @param {Event} e The event
22263      * @param {Object} data An object containing arbitrary data supplied by the drag source
22264      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22265      * underlying {@link Roo.dd.StatusProxy} can be updated
22266      */
22267     notifyOver : function(dd, e, data){
22268         var n = this.getTargetFromEvent(e);
22269         if(!n){ // not over valid drop target
22270             if(this.lastOverNode){
22271                 this.onNodeOut(this.lastOverNode, dd, e, data);
22272                 this.lastOverNode = null;
22273             }
22274             return this.onContainerOver(dd, e, data);
22275         }
22276         if(this.lastOverNode != n){
22277             if(this.lastOverNode){
22278                 this.onNodeOut(this.lastOverNode, dd, e, data);
22279             }
22280             this.onNodeEnter(n, dd, e, data);
22281             this.lastOverNode = n;
22282         }
22283         return this.onNodeOver(n, dd, e, data);
22284     },
22285
22286     /**
22287      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22288      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22289      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22290      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22291      * @param {Event} e The event
22292      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22293      */
22294     notifyOut : function(dd, e, data){
22295         if(this.lastOverNode){
22296             this.onNodeOut(this.lastOverNode, dd, e, data);
22297             this.lastOverNode = null;
22298         }
22299     },
22300
22301     /**
22302      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22303      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22304      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22305      * otherwise it will call {@link #onContainerDrop}.
22306      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22307      * @param {Event} e The event
22308      * @param {Object} data An object containing arbitrary data supplied by the drag source
22309      * @return {Boolean} True if the drop was valid, else false
22310      */
22311     notifyDrop : function(dd, e, data){
22312         if(this.lastOverNode){
22313             this.onNodeOut(this.lastOverNode, dd, e, data);
22314             this.lastOverNode = null;
22315         }
22316         var n = this.getTargetFromEvent(e);
22317         return n ?
22318             this.onNodeDrop(n, dd, e, data) :
22319             this.onContainerDrop(dd, e, data);
22320     },
22321
22322     // private
22323     triggerCacheRefresh : function(){
22324         Roo.dd.DDM.refreshCache(this.groups);
22325     }  
22326 });