roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {
69                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70                     window.addEventListener('touchstart', function __set_has_touch__ () {
71                         Roo.isTouch = true;
72                         window.removeEventListener('touchstart', __set_has_touch__);
73                     });
74                     return false; // no touch on chrome!?
75                 }
76                 document.createEvent("TouchEvent");  
77                 return true;  
78             } catch (e) {  
79                 return false;  
80             } 
81             
82         })();
83     // remove css image flicker
84         if(isIE && !isIE7){
85         try{
86             document.execCommand("BackgroundImageCache", false, true);
87         }catch(e){}
88     }
89     
90     Roo.apply(Roo, {
91         /**
92          * True if the browser is in strict mode
93          * @type Boolean
94          */
95         isStrict : isStrict,
96         /**
97          * True if the page is running over SSL
98          * @type Boolean
99          */
100         isSecure : isSecure,
101         /**
102          * True when the document is fully initialized and ready for action
103          * @type Boolean
104          */
105         isReady : false,
106         /**
107          * Turn on debugging output (currently only the factory uses this)
108          * @type Boolean
109          */
110         
111         debug: false,
112
113         /**
114          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
115          * @type Boolean
116          */
117         enableGarbageCollector : true,
118
119         /**
120          * True to automatically purge event listeners after uncaching an element (defaults to false).
121          * Note: this only happens if enableGarbageCollector is true.
122          * @type Boolean
123          */
124         enableListenerCollection:false,
125
126         /**
127          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128          * the IE insecure content warning (defaults to javascript:false).
129          * @type String
130          */
131         SSL_SECURE_URL : "javascript:false",
132
133         /**
134          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
136          * @type String
137          */
138         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
139
140         emptyFn : function(){},
141         
142         /**
143          * Copies all the properties of config to obj if they don't already exist.
144          * @param {Object} obj The receiver of the properties
145          * @param {Object} config The source of the properties
146          * @return {Object} returns obj
147          */
148         applyIf : function(o, c){
149             if(o && c){
150                 for(var p in c){
151                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
152                 }
153             }
154             return o;
155         },
156
157         /**
158          * Applies event listeners to elements by selectors when the document is ready.
159          * The event name is specified with an @ suffix.
160 <pre><code>
161 Roo.addBehaviors({
162    // add a listener for click on all anchors in element with id foo
163    '#foo a@click' : function(e, t){
164        // do something
165    },
166
167    // add the same listener to multiple selectors (separated by comma BEFORE the @)
168    '#foo a, #bar span.some-class@mouseover' : function(){
169        // do something
170    }
171 });
172 </code></pre>
173          * @param {Object} obj The list of behaviors to apply
174          */
175         addBehaviors : function(o){
176             if(!Roo.isReady){
177                 Roo.onReady(function(){
178                     Roo.addBehaviors(o);
179                 });
180                 return;
181             }
182             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
183             for(var b in o){
184                 var parts = b.split('@');
185                 if(parts[1]){ // for Object prototype breakers
186                     var s = parts[0];
187                     if(!cache[s]){
188                         cache[s] = Roo.select(s);
189                     }
190                     cache[s].on(parts[1], o[b]);
191                 }
192             }
193             cache = null;
194         },
195
196         /**
197          * Generates unique ids. If the element already has an id, it is unchanged
198          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200          * @return {String} The generated Id.
201          */
202         id : function(el, prefix){
203             prefix = prefix || "roo-gen";
204             el = Roo.getDom(el);
205             var id = prefix + (++idSeed);
206             return el ? (el.id ? el.id : (el.id = id)) : id;
207         },
208          
209        
210         /**
211          * Extends one class with another class and optionally overrides members with the passed literal. This class
212          * also adds the function "override()" to the class that can be used to override
213          * members on an instance.
214          * @param {Object} subclass The class inheriting the functionality
215          * @param {Object} superclass The class being extended
216          * @param {Object} overrides (optional) A literal with members
217          * @method extend
218          */
219         extend : function(){
220             // inline overrides
221             var io = function(o){
222                 for(var m in o){
223                     this[m] = o[m];
224                 }
225             };
226             return function(sb, sp, overrides){
227                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
228                     overrides = sp;
229                     sp = sb;
230                     sb = function(){sp.apply(this, arguments);};
231                 }
232                 var F = function(){}, sbp, spp = sp.prototype;
233                 F.prototype = spp;
234                 sbp = sb.prototype = new F();
235                 sbp.constructor=sb;
236                 sb.superclass=spp;
237                 
238                 if(spp.constructor == Object.prototype.constructor){
239                     spp.constructor=sp;
240                    
241                 }
242                 
243                 sb.override = function(o){
244                     Roo.override(sb, o);
245                 };
246                 sbp.override = io;
247                 Roo.override(sb, overrides);
248                 return sb;
249             };
250         }(),
251
252         /**
253          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
254          * Usage:<pre><code>
255 Roo.override(MyClass, {
256     newMethod1: function(){
257         // etc.
258     },
259     newMethod2: function(foo){
260         // etc.
261     }
262 });
263  </code></pre>
264          * @param {Object} origclass The class to override
265          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
266          * containing one or more methods.
267          * @method override
268          */
269         override : function(origclass, overrides){
270             if(overrides){
271                 var p = origclass.prototype;
272                 for(var method in overrides){
273                     p[method] = overrides[method];
274                 }
275             }
276         },
277         /**
278          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
279          * <pre><code>
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
283 </code></pre>
284          * @param {String} namespace1
285          * @param {String} namespace2
286          * @param {String} etc
287          * @method namespace
288          */
289         namespace : function(){
290             var a=arguments, o=null, i, j, d, rt;
291             for (i=0; i<a.length; ++i) {
292                 d=a[i].split(".");
293                 rt = d[0];
294                 /** eval:var:o */
295                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296                 for (j=1; j<d.length; ++j) {
297                     o[d[j]]=o[d[j]] || {};
298                     o=o[d[j]];
299                 }
300             }
301         },
302         /**
303          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
304          * <pre><code>
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
307 </code></pre>
308          * @param {String} classname
309          * @param {String} namespace (optional)
310          * @method factory
311          */
312          
313         factory : function(c, ns)
314         {
315             // no xtype, no ns or c.xns - or forced off by c.xns
316             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
317                 return c;
318             }
319             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320             if (c.constructor == ns[c.xtype]) {// already created...
321                 return c;
322             }
323             if (ns[c.xtype]) {
324                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325                 var ret = new ns[c.xtype](c);
326                 ret.xns = false;
327                 return ret;
328             }
329             c.xns = false; // prevent recursion..
330             return c;
331         },
332          /**
333          * Logs to console if it can.
334          *
335          * @param {String|Object} string
336          * @method log
337          */
338         log : function(s)
339         {
340             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
341                 return; // alerT?
342             }
343             console.log(s);
344             
345         },
346         /**
347          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
348          * @param {Object} o
349          * @return {String}
350          */
351         urlEncode : function(o){
352             if(!o){
353                 return "";
354             }
355             var buf = [];
356             for(var key in o){
357                 var ov = o[key], k = Roo.encodeURIComponent(key);
358                 var type = typeof ov;
359                 if(type == 'undefined'){
360                     buf.push(k, "=&");
361                 }else if(type != "function" && type != "object"){
362                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363                 }else if(ov instanceof Array){
364                     if (ov.length) {
365                             for(var i = 0, len = ov.length; i < len; i++) {
366                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
367                             }
368                         } else {
369                             buf.push(k, "=&");
370                         }
371                 }
372             }
373             buf.pop();
374             return buf.join("");
375         },
376          /**
377          * Safe version of encodeURIComponent
378          * @param {String} data 
379          * @return {String} 
380          */
381         
382         encodeURIComponent : function (data)
383         {
384             try {
385                 return encodeURIComponent(data);
386             } catch(e) {} // should be an uri encode error.
387             
388             if (data == '' || data == null){
389                return '';
390             }
391             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392             function nibble_to_hex(nibble){
393                 var chars = '0123456789ABCDEF';
394                 return chars.charAt(nibble);
395             }
396             data = data.toString();
397             var buffer = '';
398             for(var i=0; i<data.length; i++){
399                 var c = data.charCodeAt(i);
400                 var bs = new Array();
401                 if (c > 0x10000){
402                         // 4 bytes
403                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406                     bs[3] = 0x80 | (c & 0x3F);
407                 }else if (c > 0x800){
408                          // 3 bytes
409                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411                     bs[2] = 0x80 | (c & 0x3F);
412                 }else if (c > 0x80){
413                        // 2 bytes
414                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415                     bs[1] = 0x80 | (c & 0x3F);
416                 }else{
417                         // 1 byte
418                     bs[0] = c;
419                 }
420                 for(var j=0; j<bs.length; j++){
421                     var b = bs[j];
422                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
423                             + nibble_to_hex(b &0x0F);
424                     buffer += '%'+hex;
425                }
426             }
427             return buffer;    
428              
429         },
430
431         /**
432          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
433          * @param {String} string
434          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435          * @return {Object} A literal with members
436          */
437         urlDecode : function(string, overwrite){
438             if(!string || !string.length){
439                 return {};
440             }
441             var obj = {};
442             var pairs = string.split('&');
443             var pair, name, value;
444             for(var i = 0, len = pairs.length; i < len; i++){
445                 pair = pairs[i].split('=');
446                 name = decodeURIComponent(pair[0]);
447                 value = decodeURIComponent(pair[1]);
448                 if(overwrite !== true){
449                     if(typeof obj[name] == "undefined"){
450                         obj[name] = value;
451                     }else if(typeof obj[name] == "string"){
452                         obj[name] = [obj[name]];
453                         obj[name].push(value);
454                     }else{
455                         obj[name].push(value);
456                     }
457                 }else{
458                     obj[name] = value;
459                 }
460             }
461             return obj;
462         },
463
464         /**
465          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466          * passed array is not really an array, your function is called once with it.
467          * The supplied function is called with (Object item, Number index, Array allItems).
468          * @param {Array/NodeList/Mixed} array
469          * @param {Function} fn
470          * @param {Object} scope
471          */
472         each : function(array, fn, scope){
473             if(typeof array.length == "undefined" || typeof array == "string"){
474                 array = [array];
475             }
476             for(var i = 0, len = array.length; i < len; i++){
477                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
478             }
479         },
480
481         // deprecated
482         combine : function(){
483             var as = arguments, l = as.length, r = [];
484             for(var i = 0; i < l; i++){
485                 var a = as[i];
486                 if(a instanceof Array){
487                     r = r.concat(a);
488                 }else if(a.length !== undefined && !a.substr){
489                     r = r.concat(Array.prototype.slice.call(a, 0));
490                 }else{
491                     r.push(a);
492                 }
493             }
494             return r;
495         },
496
497         /**
498          * Escapes the passed string for use in a regular expression
499          * @param {String} str
500          * @return {String}
501          */
502         escapeRe : function(s) {
503             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
504         },
505
506         // internal
507         callback : function(cb, scope, args, delay){
508             if(typeof cb == "function"){
509                 if(delay){
510                     cb.defer(delay, scope, args || []);
511                 }else{
512                     cb.apply(scope, args || []);
513                 }
514             }
515         },
516
517         /**
518          * Return the dom node for the passed string (id), dom node, or Roo.Element
519          * @param {String/HTMLElement/Roo.Element} el
520          * @return HTMLElement
521          */
522         getDom : function(el){
523             if(!el){
524                 return null;
525             }
526             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
527         },
528
529         /**
530         * Shorthand for {@link Roo.ComponentMgr#get}
531         * @param {String} id
532         * @return Roo.Component
533         */
534         getCmp : function(id){
535             return Roo.ComponentMgr.get(id);
536         },
537          
538         num : function(v, defaultValue){
539             if(typeof v != 'number'){
540                 return defaultValue;
541             }
542             return v;
543         },
544
545         destroy : function(){
546             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
547                 var as = a[i];
548                 if(as){
549                     if(as.dom){
550                         as.removeAllListeners();
551                         as.remove();
552                         continue;
553                     }
554                     if(typeof as.purgeListeners == 'function'){
555                         as.purgeListeners();
556                     }
557                     if(typeof as.destroy == 'function'){
558                         as.destroy();
559                     }
560                 }
561             }
562         },
563
564         // inpired by a similar function in mootools library
565         /**
566          * Returns the type of object that is passed in. If the object passed in is null or undefined it
567          * return false otherwise it returns one of the following values:<ul>
568          * <li><b>string</b>: If the object passed is a string</li>
569          * <li><b>number</b>: If the object passed is a number</li>
570          * <li><b>boolean</b>: If the object passed is a boolean value</li>
571          * <li><b>function</b>: If the object passed is a function reference</li>
572          * <li><b>object</b>: If the object passed is an object</li>
573          * <li><b>array</b>: If the object passed is an array</li>
574          * <li><b>regexp</b>: If the object passed is a regular expression</li>
575          * <li><b>element</b>: If the object passed is a DOM Element</li>
576          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579          * @param {Mixed} object
580          * @return {String}
581          */
582         type : function(o){
583             if(o === undefined || o === null){
584                 return false;
585             }
586             if(o.htmlElement){
587                 return 'element';
588             }
589             var t = typeof o;
590             if(t == 'object' && o.nodeName) {
591                 switch(o.nodeType) {
592                     case 1: return 'element';
593                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
594                 }
595             }
596             if(t == 'object' || t == 'function') {
597                 switch(o.constructor) {
598                     case Array: return 'array';
599                     case RegExp: return 'regexp';
600                 }
601                 if(typeof o.length == 'number' && typeof o.item == 'function') {
602                     return 'nodelist';
603                 }
604             }
605             return t;
606         },
607
608         /**
609          * Returns true if the passed value is null, undefined or an empty string (optional).
610          * @param {Mixed} value The value to test
611          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
612          * @return {Boolean}
613          */
614         isEmpty : function(v, allowBlank){
615             return v === null || v === undefined || (!allowBlank ? v === '' : false);
616         },
617         
618         /** @type Boolean */
619         isOpera : isOpera,
620         /** @type Boolean */
621         isSafari : isSafari,
622         /** @type Boolean */
623         isFirefox : isFirefox,
624         /** @type Boolean */
625         isIE : isIE,
626         /** @type Boolean */
627         isIE7 : isIE7,
628         /** @type Boolean */
629         isIE11 : isIE11,
630         /** @type Boolean */
631         isGecko : isGecko,
632         /** @type Boolean */
633         isBorderBox : isBorderBox,
634         /** @type Boolean */
635         isWindows : isWindows,
636         /** @type Boolean */
637         isLinux : isLinux,
638         /** @type Boolean */
639         isMac : isMac,
640         /** @type Boolean */
641         isIOS : isIOS,
642         /** @type Boolean */
643         isTouch : isTouch,
644
645         /**
646          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647          * you may want to set this to true.
648          * @type Boolean
649          */
650         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
651         
652         
653                 
654         /**
655          * Selects a single element as a Roo Element
656          * This is about as close as you can get to jQuery's $('do crazy stuff')
657          * @param {String} selector The selector/xpath query
658          * @param {Node} root (optional) The start of the query (defaults to document).
659          * @return {Roo.Element}
660          */
661         selectNode : function(selector, root) 
662         {
663             var node = Roo.DomQuery.selectNode(selector,root);
664             return node ? Roo.get(node) : new Roo.Element(false);
665         }
666         
667     });
668
669
670 })();
671
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
674                 "Roo.app", "Roo.ux",
675                 "Roo.bootstrap",
676                 "Roo.bootstrap.dash");
677 /*
678  * Based on:
679  * Ext JS Library 1.1.1
680  * Copyright(c) 2006-2007, Ext JS, LLC.
681  *
682  * Originally Released Under LGPL - original licence link has changed is not relivant.
683  *
684  * Fork - LGPL
685  * <script type="text/javascript">
686  */
687
688 (function() {    
689     // wrappedn so fnCleanup is not in global scope...
690     if(Roo.isIE) {
691         function fnCleanUp() {
692             var p = Function.prototype;
693             delete p.createSequence;
694             delete p.defer;
695             delete p.createDelegate;
696             delete p.createCallback;
697             delete p.createInterceptor;
698
699             window.detachEvent("onunload", fnCleanUp);
700         }
701         window.attachEvent("onunload", fnCleanUp);
702     }
703 })();
704
705
706 /**
707  * @class Function
708  * These functions are available on every Function object (any JavaScript function).
709  */
710 Roo.apply(Function.prototype, {
711      /**
712      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714      * Will create a function that is bound to those 2 args.
715      * @return {Function} The new function
716     */
717     createCallback : function(/*args...*/){
718         // make args available, in function below
719         var args = arguments;
720         var method = this;
721         return function() {
722             return method.apply(window, args);
723         };
724     },
725
726     /**
727      * Creates a delegate (callback) that sets the scope to obj.
728      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729      * Will create a function that is automatically scoped to this.
730      * @param {Object} obj (optional) The object for which the scope is set
731      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733      *                                             if a number the args are inserted at the specified position
734      * @return {Function} The new function
735      */
736     createDelegate : function(obj, args, appendArgs){
737         var method = this;
738         return function() {
739             var callArgs = args || arguments;
740             if(appendArgs === true){
741                 callArgs = Array.prototype.slice.call(arguments, 0);
742                 callArgs = callArgs.concat(args);
743             }else if(typeof appendArgs == "number"){
744                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
747             }
748             return method.apply(obj || window, callArgs);
749         };
750     },
751
752     /**
753      * Calls this function after the number of millseconds specified.
754      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755      * @param {Object} obj (optional) The object for which the scope is set
756      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758      *                                             if a number the args are inserted at the specified position
759      * @return {Number} The timeout id that can be used with clearTimeout
760      */
761     defer : function(millis, obj, args, appendArgs){
762         var fn = this.createDelegate(obj, args, appendArgs);
763         if(millis){
764             return setTimeout(fn, millis);
765         }
766         fn();
767         return 0;
768     },
769     /**
770      * Create a combined function call sequence of the original function + the passed function.
771      * The resulting function returns the results of the original function.
772      * The passed fcn is called with the parameters of the original function
773      * @param {Function} fcn The function to sequence
774      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775      * @return {Function} The new function
776      */
777     createSequence : function(fcn, scope){
778         if(typeof fcn != "function"){
779             return this;
780         }
781         var method = this;
782         return function() {
783             var retval = method.apply(this || window, arguments);
784             fcn.apply(scope || this || window, arguments);
785             return retval;
786         };
787     },
788
789     /**
790      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791      * The resulting function returns the results of the original function.
792      * The passed fcn is called with the parameters of the original function.
793      * @addon
794      * @param {Function} fcn The function to call before the original
795      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796      * @return {Function} The new function
797      */
798     createInterceptor : function(fcn, scope){
799         if(typeof fcn != "function"){
800             return this;
801         }
802         var method = this;
803         return function() {
804             fcn.target = this;
805             fcn.method = method;
806             if(fcn.apply(scope || this || window, arguments) === false){
807                 return;
808             }
809             return method.apply(this || window, arguments);
810         };
811     }
812 });
813 /*
814  * Based on:
815  * Ext JS Library 1.1.1
816  * Copyright(c) 2006-2007, Ext JS, LLC.
817  *
818  * Originally Released Under LGPL - original licence link has changed is not relivant.
819  *
820  * Fork - LGPL
821  * <script type="text/javascript">
822  */
823
824 Roo.applyIf(String, {
825     
826     /** @scope String */
827     
828     /**
829      * Escapes the passed string for ' and \
830      * @param {String} string The string to escape
831      * @return {String} The escaped string
832      * @static
833      */
834     escape : function(string) {
835         return string.replace(/('|\\)/g, "\\$1");
836     },
837
838     /**
839      * Pads the left side of a string with a specified character.  This is especially useful
840      * for normalizing number and date strings.  Example usage:
841      * <pre><code>
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
844 </code></pre>
845      * @param {String} string The original string
846      * @param {Number} size The total length of the output string
847      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848      * @return {String} The padded string
849      * @static
850      */
851     leftPad : function (val, size, ch) {
852         var result = new String(val);
853         if(ch === null || ch === undefined || ch === '') {
854             ch = " ";
855         }
856         while (result.length < size) {
857             result = ch + result;
858         }
859         return result;
860     },
861
862     /**
863      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
864      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
865      * <pre><code>
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
869 </code></pre>
870      * @param {String} string The tokenized string to be formatted
871      * @param {String} value1 The value to replace token {0}
872      * @param {String} value2 Etc...
873      * @return {String} The formatted string
874      * @static
875      */
876     format : function(format){
877         var args = Array.prototype.slice.call(arguments, 1);
878         return format.replace(/\{(\d+)\}/g, function(m, i){
879             return Roo.util.Format.htmlEncode(args[i]);
880         });
881     }
882 });
883
884 /**
885  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
886  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
887  * they are already different, the first value passed in is returned.  Note that this method returns the new value
888  * but does not change the current string.
889  * <pre><code>
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
892
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
895 </code></pre>
896  * @param {String} value The value to compare to the current string
897  * @param {String} other The new value to use if the string already equals the first value passed in
898  * @return {String} The new value
899  */
900  
901 String.prototype.toggle = function(value, other){
902     return this == value ? other : value;
903 };/*
904  * Based on:
905  * Ext JS Library 1.1.1
906  * Copyright(c) 2006-2007, Ext JS, LLC.
907  *
908  * Originally Released Under LGPL - original licence link has changed is not relivant.
909  *
910  * Fork - LGPL
911  * <script type="text/javascript">
912  */
913
914  /**
915  * @class Number
916  */
917 Roo.applyIf(Number.prototype, {
918     /**
919      * Checks whether or not the current number is within a desired range.  If the number is already within the
920      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921      * exceeded.  Note that this method returns the constrained value but does not change the current number.
922      * @param {Number} min The minimum number in the range
923      * @param {Number} max The maximum number in the range
924      * @return {Number} The constrained value if outside the range, otherwise the current value
925      */
926     constrain : function(min, max){
927         return Math.min(Math.max(this, min), max);
928     }
929 });/*
930  * Based on:
931  * Ext JS Library 1.1.1
932  * Copyright(c) 2006-2007, Ext JS, LLC.
933  *
934  * Originally Released Under LGPL - original licence link has changed is not relivant.
935  *
936  * Fork - LGPL
937  * <script type="text/javascript">
938  */
939  /**
940  * @class Array
941  */
942 Roo.applyIf(Array.prototype, {
943     /**
944      * 
945      * Checks whether or not the specified object exists in the array.
946      * @param {Object} o The object to check for
947      * @return {Number} The index of o in the array (or -1 if it is not found)
948      */
949     indexOf : function(o){
950        for (var i = 0, len = this.length; i < len; i++){
951               if(this[i] == o) { return i; }
952        }
953            return -1;
954     },
955
956     /**
957      * Removes the specified object from the array.  If the object is not found nothing happens.
958      * @param {Object} o The object to remove
959      */
960     remove : function(o){
961        var index = this.indexOf(o);
962        if(index != -1){
963            this.splice(index, 1);
964        }
965     },
966     /**
967      * Map (JS 1.6 compatibility)
968      * @param {Function} function  to call
969      */
970     map : function(fun )
971     {
972         var len = this.length >>> 0;
973         if (typeof fun != "function") {
974             throw new TypeError();
975         }
976         var res = new Array(len);
977         var thisp = arguments[1];
978         for (var i = 0; i < len; i++)
979         {
980             if (i in this) {
981                 res[i] = fun.call(thisp, this[i], i, this);
982             }
983         }
984
985         return res;
986     }
987     
988 });
989
990
991  
992 /*
993  * Based on:
994  * Ext JS Library 1.1.1
995  * Copyright(c) 2006-2007, Ext JS, LLC.
996  *
997  * Originally Released Under LGPL - original licence link has changed is not relivant.
998  *
999  * Fork - LGPL
1000  * <script type="text/javascript">
1001  */
1002
1003 /**
1004  * @class Date
1005  *
1006  * The date parsing and format syntax is a subset of
1007  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008  * supported will provide results equivalent to their PHP versions.
1009  *
1010  * Following is the list of all currently supported formats:
1011  *<pre>
1012 Sample date:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1014
1015 Format  Output      Description
1016 ------  ----------  --------------------------------------------------------------
1017   d      10         Day of the month, 2 digits with leading zeros
1018   D      Wed        A textual representation of a day, three letters
1019   j      10         Day of the month without leading zeros
1020   l      Wednesday  A full textual representation of the day of the week
1021   S      th         English ordinal day of month suffix, 2 chars (use with j)
1022   w      3          Numeric representation of the day of the week
1023   z      9          The julian date, or day of the year (0-365)
1024   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025   F      January    A full textual representation of the month
1026   m      01         Numeric representation of a month, with leading zeros
1027   M      Jan        Month name abbreviation, three letters
1028   n      1          Numeric representation of a month, without leading zeros
1029   t      31         Number of days in the given month
1030   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1031   Y      2007       A full numeric representation of a year, 4 digits
1032   y      07         A two digit representation of a year
1033   a      pm         Lowercase Ante meridiem and Post meridiem
1034   A      PM         Uppercase Ante meridiem and Post meridiem
1035   g      3          12-hour format of an hour without leading zeros
1036   G      15         24-hour format of an hour without leading zeros
1037   h      03         12-hour format of an hour with leading zeros
1038   H      15         24-hour format of an hour with leading zeros
1039   i      05         Minutes with leading zeros
1040   s      01         Seconds, with leading zeros
1041   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1043   T      CST        Timezone setting of the machine running the code
1044   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1045 </pre>
1046  *
1047  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1048  * <pre><code>
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d'));                         //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1052 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1053  </code></pre>
1054  *
1055  * Here are some standard date/time patterns that you might find helpful.  They
1056  * are not part of the source of Date.js, but to use them you can simply copy this
1057  * block of code into any script that is included after Date.js and they will also become
1058  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1059  * <pre><code>
1060 Date.patterns = {
1061     ISO8601Long:"Y-m-d H:i:s",
1062     ISO8601Short:"Y-m-d",
1063     ShortDate: "n/j/Y",
1064     LongDate: "l, F d, Y",
1065     FullDateTime: "l, F d, Y g:i:s A",
1066     MonthDay: "F d",
1067     ShortTime: "g:i A",
1068     LongTime: "g:i:s A",
1069     SortableDateTime: "Y-m-d\\TH:i:s",
1070     UniversalSortableDateTime: "Y-m-d H:i:sO",
1071     YearMonth: "F, Y"
1072 };
1073 </code></pre>
1074  *
1075  * Example usage:
1076  * <pre><code>
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1079  </code></pre>
1080  */
1081
1082 /*
1083  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084  * They generate precompiled functions from date formats instead of parsing and
1085  * processing the pattern every time you format a date.  These functions are available
1086  * on every Date object (any javascript function).
1087  *
1088  * The original article and download are here:
1089  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1090  *
1091  */
1092  
1093  
1094  // was in core
1095 /**
1096  Returns the number of milliseconds between this date and date
1097  @param {Date} date (optional) Defaults to now
1098  @return {Number} The diff in milliseconds
1099  @member Date getElapsed
1100  */
1101 Date.prototype.getElapsed = function(date) {
1102         return Math.abs((date || new Date()).getTime()-this.getTime());
1103 };
1104 // was in date file..
1105
1106
1107 // private
1108 Date.parseFunctions = {count:0};
1109 // private
1110 Date.parseRegexes = [];
1111 // private
1112 Date.formatFunctions = {count:0};
1113
1114 // private
1115 Date.prototype.dateFormat = function(format) {
1116     if (Date.formatFunctions[format] == null) {
1117         Date.createNewFormat(format);
1118     }
1119     var func = Date.formatFunctions[format];
1120     return this[func]();
1121 };
1122
1123
1124 /**
1125  * Formats a date given the supplied format string
1126  * @param {String} format The format string
1127  * @return {String} The formatted date
1128  * @method
1129  */
1130 Date.prototype.format = Date.prototype.dateFormat;
1131
1132 // private
1133 Date.createNewFormat = function(format) {
1134     var funcName = "format" + Date.formatFunctions.count++;
1135     Date.formatFunctions[format] = funcName;
1136     var code = "Date.prototype." + funcName + " = function(){return ";
1137     var special = false;
1138     var ch = '';
1139     for (var i = 0; i < format.length; ++i) {
1140         ch = format.charAt(i);
1141         if (!special && ch == "\\") {
1142             special = true;
1143         }
1144         else if (special) {
1145             special = false;
1146             code += "'" + String.escape(ch) + "' + ";
1147         }
1148         else {
1149             code += Date.getFormatCode(ch);
1150         }
1151     }
1152     /** eval:var:zzzzzzzzzzzzz */
1153     eval(code.substring(0, code.length - 3) + ";}");
1154 };
1155
1156 // private
1157 Date.getFormatCode = function(character) {
1158     switch (character) {
1159     case "d":
1160         return "String.leftPad(this.getDate(), 2, '0') + ";
1161     case "D":
1162         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1163     case "j":
1164         return "this.getDate() + ";
1165     case "l":
1166         return "Date.dayNames[this.getDay()] + ";
1167     case "S":
1168         return "this.getSuffix() + ";
1169     case "w":
1170         return "this.getDay() + ";
1171     case "z":
1172         return "this.getDayOfYear() + ";
1173     case "W":
1174         return "this.getWeekOfYear() + ";
1175     case "F":
1176         return "Date.monthNames[this.getMonth()] + ";
1177     case "m":
1178         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1179     case "M":
1180         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1181     case "n":
1182         return "(this.getMonth() + 1) + ";
1183     case "t":
1184         return "this.getDaysInMonth() + ";
1185     case "L":
1186         return "(this.isLeapYear() ? 1 : 0) + ";
1187     case "Y":
1188         return "this.getFullYear() + ";
1189     case "y":
1190         return "('' + this.getFullYear()).substring(2, 4) + ";
1191     case "a":
1192         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1193     case "A":
1194         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1195     case "g":
1196         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1197     case "G":
1198         return "this.getHours() + ";
1199     case "h":
1200         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1201     case "H":
1202         return "String.leftPad(this.getHours(), 2, '0') + ";
1203     case "i":
1204         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1205     case "s":
1206         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1207     case "O":
1208         return "this.getGMTOffset() + ";
1209     case "P":
1210         return "this.getGMTColonOffset() + ";
1211     case "T":
1212         return "this.getTimezone() + ";
1213     case "Z":
1214         return "(this.getTimezoneOffset() * -60) + ";
1215     default:
1216         return "'" + String.escape(character) + "' + ";
1217     }
1218 };
1219
1220 /**
1221  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1223  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1224  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1225  * string or the parse operation will fail.
1226  * Example Usage:
1227 <pre><code>
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1230
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1233
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1236
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1239 </code></pre>
1240  * @param {String} input The unparsed date as a string
1241  * @param {String} format The format the date is in
1242  * @return {Date} The parsed date
1243  * @static
1244  */
1245 Date.parseDate = function(input, format) {
1246     if (Date.parseFunctions[format] == null) {
1247         Date.createParser(format);
1248     }
1249     var func = Date.parseFunctions[format];
1250     return Date[func](input);
1251 };
1252 /**
1253  * @private
1254  */
1255
1256 Date.createParser = function(format) {
1257     var funcName = "parse" + Date.parseFunctions.count++;
1258     var regexNum = Date.parseRegexes.length;
1259     var currentGroup = 1;
1260     Date.parseFunctions[format] = funcName;
1261
1262     var code = "Date." + funcName + " = function(input){\n"
1263         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264         + "var d = new Date();\n"
1265         + "y = d.getFullYear();\n"
1266         + "m = d.getMonth();\n"
1267         + "d = d.getDate();\n"
1268         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270         + "if (results && results.length > 0) {";
1271     var regex = "";
1272
1273     var special = false;
1274     var ch = '';
1275     for (var i = 0; i < format.length; ++i) {
1276         ch = format.charAt(i);
1277         if (!special && ch == "\\") {
1278             special = true;
1279         }
1280         else if (special) {
1281             special = false;
1282             regex += String.escape(ch);
1283         }
1284         else {
1285             var obj = Date.formatCodeToRegex(ch, currentGroup);
1286             currentGroup += obj.g;
1287             regex += obj.s;
1288             if (obj.g && obj.c) {
1289                 code += obj.c;
1290             }
1291         }
1292     }
1293
1294     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295         + "{v = new Date(y, m, d, h, i, s);}\n"
1296         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297         + "{v = new Date(y, m, d, h, i);}\n"
1298         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299         + "{v = new Date(y, m, d, h);}\n"
1300         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301         + "{v = new Date(y, m, d);}\n"
1302         + "else if (y >= 0 && m >= 0)\n"
1303         + "{v = new Date(y, m);}\n"
1304         + "else if (y >= 0)\n"
1305         + "{v = new Date(y);}\n"
1306         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1309         + ";}";
1310
1311     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312     /** eval:var:zzzzzzzzzzzzz */
1313     eval(code);
1314 };
1315
1316 // private
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318     switch (character) {
1319     case "D":
1320         return {g:0,
1321         c:null,
1322         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1323     case "j":
1324         return {g:1,
1325             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326             s:"(\\d{1,2})"}; // day of month without leading zeroes
1327     case "d":
1328         return {g:1,
1329             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330             s:"(\\d{2})"}; // day of month with leading zeroes
1331     case "l":
1332         return {g:0,
1333             c:null,
1334             s:"(?:" + Date.dayNames.join("|") + ")"};
1335     case "S":
1336         return {g:0,
1337             c:null,
1338             s:"(?:st|nd|rd|th)"};
1339     case "w":
1340         return {g:0,
1341             c:null,
1342             s:"\\d"};
1343     case "z":
1344         return {g:0,
1345             c:null,
1346             s:"(?:\\d{1,3})"};
1347     case "W":
1348         return {g:0,
1349             c:null,
1350             s:"(?:\\d{2})"};
1351     case "F":
1352         return {g:1,
1353             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354             s:"(" + Date.monthNames.join("|") + ")"};
1355     case "M":
1356         return {g:1,
1357             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1359     case "n":
1360         return {g:1,
1361             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1363     case "m":
1364         return {g:1,
1365             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1367     case "t":
1368         return {g:0,
1369             c:null,
1370             s:"\\d{1,2}"};
1371     case "L":
1372         return {g:0,
1373             c:null,
1374             s:"(?:1|0)"};
1375     case "Y":
1376         return {g:1,
1377             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1378             s:"(\\d{4})"};
1379     case "y":
1380         return {g:1,
1381             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1383             s:"(\\d{1,2})"};
1384     case "a":
1385         return {g:1,
1386             c:"if (results[" + currentGroup + "] == 'am') {\n"
1387                 + "if (h == 12) { h = 0; }\n"
1388                 + "} else { if (h < 12) { h += 12; }}",
1389             s:"(am|pm)"};
1390     case "A":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(AM|PM)"};
1396     case "g":
1397     case "G":
1398         return {g:1,
1399             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1401     case "h":
1402     case "H":
1403         return {g:1,
1404             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1406     case "i":
1407         return {g:1,
1408             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1409             s:"(\\d{2})"};
1410     case "s":
1411         return {g:1,
1412             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1413             s:"(\\d{2})"};
1414     case "O":
1415         return {g:1,
1416             c:[
1417                 "o = results[", currentGroup, "];\n",
1418                 "var sn = o.substring(0,1);\n", // get + / - sign
1419                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1423             ].join(""),
1424             s:"([+\-]\\d{2,4})"};
1425     
1426     
1427     case "P":
1428         return {g:1,
1429                 c:[
1430                    "o = results[", currentGroup, "];\n",
1431                    "var sn = o.substring(0,1);\n",
1432                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433                    "var mn = o.substring(4,6) % 60;\n",
1434                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1436             ].join(""),
1437             s:"([+\-]\\d{4})"};
1438     case "T":
1439         return {g:0,
1440             c:null,
1441             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1442     case "Z":
1443         return {g:1,
1444             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1447     default:
1448         return {g:0,
1449             c:null,
1450             s:String.escape(character)};
1451     }
1452 };
1453
1454 /**
1455  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456  * @return {String} The abbreviated timezone name (e.g. 'CST')
1457  */
1458 Date.prototype.getTimezone = function() {
1459     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1460 };
1461
1462 /**
1463  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1465  */
1466 Date.prototype.getGMTOffset = function() {
1467     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1470 };
1471
1472 /**
1473  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474  * @return {String} 2-characters representing hours and 2-characters representing minutes
1475  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1476  */
1477 Date.prototype.getGMTColonOffset = function() {
1478         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1480                 + ":"
1481                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1482 }
1483
1484 /**
1485  * Get the numeric day number of the year, adjusted for leap year.
1486  * @return {Number} 0 through 364 (365 in leap years)
1487  */
1488 Date.prototype.getDayOfYear = function() {
1489     var num = 0;
1490     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491     for (var i = 0; i < this.getMonth(); ++i) {
1492         num += Date.daysInMonth[i];
1493     }
1494     return num + this.getDate() - 1;
1495 };
1496
1497 /**
1498  * Get the string representation of the numeric week number of the year
1499  * (equivalent to the format specifier 'W').
1500  * @return {String} '00' through '52'
1501  */
1502 Date.prototype.getWeekOfYear = function() {
1503     // Skip to Thursday of this week
1504     var now = this.getDayOfYear() + (4 - this.getDay());
1505     // Find the first Thursday of the year
1506     var jan1 = new Date(this.getFullYear(), 0, 1);
1507     var then = (7 - jan1.getDay() + 4);
1508     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1509 };
1510
1511 /**
1512  * Whether or not the current date is in a leap year.
1513  * @return {Boolean} True if the current date is in a leap year, else false
1514  */
1515 Date.prototype.isLeapYear = function() {
1516     var year = this.getFullYear();
1517     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1518 };
1519
1520 /**
1521  * Get the first day of the current month, adjusted for leap year.  The returned value
1522  * is the numeric day index within the week (0-6) which can be used in conjunction with
1523  * the {@link #monthNames} array to retrieve the textual day name.
1524  * Example:
1525  *<pre><code>
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1528 </code></pre>
1529  * @return {Number} The day number (0-6)
1530  */
1531 Date.prototype.getFirstDayOfMonth = function() {
1532     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533     return (day < 0) ? (day + 7) : day;
1534 };
1535
1536 /**
1537  * Get the last day of the current month, adjusted for leap year.  The returned value
1538  * is the numeric day index within the week (0-6) which can be used in conjunction with
1539  * the {@link #monthNames} array to retrieve the textual day name.
1540  * Example:
1541  *<pre><code>
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1544 </code></pre>
1545  * @return {Number} The day number (0-6)
1546  */
1547 Date.prototype.getLastDayOfMonth = function() {
1548     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549     return (day < 0) ? (day + 7) : day;
1550 };
1551
1552
1553 /**
1554  * Get the first date of this date's month
1555  * @return {Date}
1556  */
1557 Date.prototype.getFirstDateOfMonth = function() {
1558     return new Date(this.getFullYear(), this.getMonth(), 1);
1559 };
1560
1561 /**
1562  * Get the last date of this date's month
1563  * @return {Date}
1564  */
1565 Date.prototype.getLastDateOfMonth = function() {
1566     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1567 };
1568 /**
1569  * Get the number of days in the current month, adjusted for leap year.
1570  * @return {Number} The number of days in the month
1571  */
1572 Date.prototype.getDaysInMonth = function() {
1573     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574     return Date.daysInMonth[this.getMonth()];
1575 };
1576
1577 /**
1578  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579  * @return {String} 'st, 'nd', 'rd' or 'th'
1580  */
1581 Date.prototype.getSuffix = function() {
1582     switch (this.getDate()) {
1583         case 1:
1584         case 21:
1585         case 31:
1586             return "st";
1587         case 2:
1588         case 22:
1589             return "nd";
1590         case 3:
1591         case 23:
1592             return "rd";
1593         default:
1594             return "th";
1595     }
1596 };
1597
1598 // private
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1600
1601 /**
1602  * An array of textual month names.
1603  * Override these values for international dates, for example...
1604  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1605  * @type Array
1606  * @static
1607  */
1608 Date.monthNames =
1609    ["January",
1610     "February",
1611     "March",
1612     "April",
1613     "May",
1614     "June",
1615     "July",
1616     "August",
1617     "September",
1618     "October",
1619     "November",
1620     "December"];
1621
1622 /**
1623  * An array of textual day names.
1624  * Override these values for international dates, for example...
1625  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1626  * @type Array
1627  * @static
1628  */
1629 Date.dayNames =
1630    ["Sunday",
1631     "Monday",
1632     "Tuesday",
1633     "Wednesday",
1634     "Thursday",
1635     "Friday",
1636     "Saturday"];
1637
1638 // private
1639 Date.y2kYear = 50;
1640 // private
1641 Date.monthNumbers = {
1642     Jan:0,
1643     Feb:1,
1644     Mar:2,
1645     Apr:3,
1646     May:4,
1647     Jun:5,
1648     Jul:6,
1649     Aug:7,
1650     Sep:8,
1651     Oct:9,
1652     Nov:10,
1653     Dec:11};
1654
1655 /**
1656  * Creates and returns a new Date instance with the exact same date value as the called instance.
1657  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658  * variable will also be changed.  When the intention is to create a new variable that will not
1659  * modify the original instance, you should create a clone.
1660  *
1661  * Example of correctly cloning a date:
1662  * <pre><code>
1663 //wrong way:
1664 var orig = new Date('10/1/2006');
1665 var copy = orig;
1666 copy.setDate(5);
1667 document.write(orig);  //returns 'Thu Oct 05 2006'!
1668
1669 //correct way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 01 2006'
1674 </code></pre>
1675  * @return {Date} The new Date instance
1676  */
1677 Date.prototype.clone = function() {
1678         return new Date(this.getTime());
1679 };
1680
1681 /**
1682  * Clears any time information from this date
1683  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684  @return {Date} this or the clone
1685  */
1686 Date.prototype.clearTime = function(clone){
1687     if(clone){
1688         return this.clone().clearTime();
1689     }
1690     this.setHours(0);
1691     this.setMinutes(0);
1692     this.setSeconds(0);
1693     this.setMilliseconds(0);
1694     return this;
1695 };
1696
1697 // private
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700     Date.brokenSetMonth = Date.prototype.setMonth;
1701         Date.prototype.setMonth = function(num){
1702                 if(num <= -1){
1703                         var n = Math.ceil(-num);
1704                         var back_year = Math.ceil(n/12);
1705                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1706                         this.setFullYear(this.getFullYear() - back_year);
1707                         return Date.brokenSetMonth.call(this, month);
1708                 } else {
1709                         return Date.brokenSetMonth.apply(this, arguments);
1710                 }
1711         };
1712 }
1713
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MILLI = "ms";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.SECOND = "s";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.MINUTE = "mi";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.HOUR = "h";
1730 /** Date interval constant 
1731 * @static 
1732 * @type String */
1733 Date.DAY = "d";
1734 /** Date interval constant 
1735 * @static 
1736 * @type String */
1737 Date.MONTH = "mo";
1738 /** Date interval constant 
1739 * @static 
1740 * @type String */
1741 Date.YEAR = "y";
1742
1743 /**
1744  * Provides a convenient method of performing basic date arithmetic.  This method
1745  * does not modify the Date instance being called - it creates and returns
1746  * a new Date instance containing the resulting date value.
1747  *
1748  * Examples:
1749  * <pre><code>
1750 //Basic usage:
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1753
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1757
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1761  </code></pre>
1762  *
1763  * @param {String} interval   A valid date interval enum value
1764  * @param {Number} value      The amount to add to the current date
1765  * @return {Date} The new Date instance
1766  */
1767 Date.prototype.add = function(interval, value){
1768   var d = this.clone();
1769   if (!interval || value === 0) { return d; }
1770   switch(interval.toLowerCase()){
1771     case Date.MILLI:
1772       d.setMilliseconds(this.getMilliseconds() + value);
1773       break;
1774     case Date.SECOND:
1775       d.setSeconds(this.getSeconds() + value);
1776       break;
1777     case Date.MINUTE:
1778       d.setMinutes(this.getMinutes() + value);
1779       break;
1780     case Date.HOUR:
1781       d.setHours(this.getHours() + value);
1782       break;
1783     case Date.DAY:
1784       d.setDate(this.getDate() + value);
1785       break;
1786     case Date.MONTH:
1787       var day = this.getDate();
1788       if(day > 28){
1789           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1790       }
1791       d.setDate(day);
1792       d.setMonth(this.getMonth() + value);
1793       break;
1794     case Date.YEAR:
1795       d.setFullYear(this.getFullYear() + value);
1796       break;
1797   }
1798   return d;
1799 };
1800 /*
1801  * Based on:
1802  * Ext JS Library 1.1.1
1803  * Copyright(c) 2006-2007, Ext JS, LLC.
1804  *
1805  * Originally Released Under LGPL - original licence link has changed is not relivant.
1806  *
1807  * Fork - LGPL
1808  * <script type="text/javascript">
1809  */
1810
1811 /**
1812  * @class Roo.lib.Dom
1813  * @static
1814  * 
1815  * Dom utils (from YIU afaik)
1816  * 
1817  **/
1818 Roo.lib.Dom = {
1819     /**
1820      * Get the view width
1821      * @param {Boolean} full True will get the full document, otherwise it's the view width
1822      * @return {Number} The width
1823      */
1824      
1825     getViewWidth : function(full) {
1826         return full ? this.getDocumentWidth() : this.getViewportWidth();
1827     },
1828     /**
1829      * Get the view height
1830      * @param {Boolean} full True will get the full document, otherwise it's the view height
1831      * @return {Number} The height
1832      */
1833     getViewHeight : function(full) {
1834         return full ? this.getDocumentHeight() : this.getViewportHeight();
1835     },
1836
1837     getDocumentHeight: function() {
1838         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839         return Math.max(scrollHeight, this.getViewportHeight());
1840     },
1841
1842     getDocumentWidth: function() {
1843         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844         return Math.max(scrollWidth, this.getViewportWidth());
1845     },
1846
1847     getViewportHeight: function() {
1848         var height = self.innerHeight;
1849         var mode = document.compatMode;
1850
1851         if ((mode || Roo.isIE) && !Roo.isOpera) {
1852             height = (mode == "CSS1Compat") ?
1853                      document.documentElement.clientHeight :
1854                      document.body.clientHeight;
1855         }
1856
1857         return height;
1858     },
1859
1860     getViewportWidth: function() {
1861         var width = self.innerWidth;
1862         var mode = document.compatMode;
1863
1864         if (mode || Roo.isIE) {
1865             width = (mode == "CSS1Compat") ?
1866                     document.documentElement.clientWidth :
1867                     document.body.clientWidth;
1868         }
1869         return width;
1870     },
1871
1872     isAncestor : function(p, c) {
1873         p = Roo.getDom(p);
1874         c = Roo.getDom(c);
1875         if (!p || !c) {
1876             return false;
1877         }
1878
1879         if (p.contains && !Roo.isSafari) {
1880             return p.contains(c);
1881         } else if (p.compareDocumentPosition) {
1882             return !!(p.compareDocumentPosition(c) & 16);
1883         } else {
1884             var parent = c.parentNode;
1885             while (parent) {
1886                 if (parent == p) {
1887                     return true;
1888                 }
1889                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1890                     return false;
1891                 }
1892                 parent = parent.parentNode;
1893             }
1894             return false;
1895         }
1896     },
1897
1898     getRegion : function(el) {
1899         return Roo.lib.Region.getRegion(el);
1900     },
1901
1902     getY : function(el) {
1903         return this.getXY(el)[1];
1904     },
1905
1906     getX : function(el) {
1907         return this.getXY(el)[0];
1908     },
1909
1910     getXY : function(el) {
1911         var p, pe, b, scroll, bd = document.body;
1912         el = Roo.getDom(el);
1913         var fly = Roo.lib.AnimBase.fly;
1914         if (el.getBoundingClientRect) {
1915             b = el.getBoundingClientRect();
1916             scroll = fly(document).getScroll();
1917             return [b.left + scroll.left, b.top + scroll.top];
1918         }
1919         var x = 0, y = 0;
1920
1921         p = el;
1922
1923         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1924
1925         while (p) {
1926
1927             x += p.offsetLeft;
1928             y += p.offsetTop;
1929
1930             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1931                 hasAbsolute = true;
1932             }
1933
1934             if (Roo.isGecko) {
1935                 pe = fly(p);
1936
1937                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1939
1940
1941                 x += bl;
1942                 y += bt;
1943
1944
1945                 if (p != el && pe.getStyle('overflow') != 'visible') {
1946                     x += bl;
1947                     y += bt;
1948                 }
1949             }
1950             p = p.offsetParent;
1951         }
1952
1953         if (Roo.isSafari && hasAbsolute) {
1954             x -= bd.offsetLeft;
1955             y -= bd.offsetTop;
1956         }
1957
1958         if (Roo.isGecko && !hasAbsolute) {
1959             var dbd = fly(bd);
1960             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1962         }
1963
1964         p = el.parentNode;
1965         while (p && p != bd) {
1966             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1967                 x -= p.scrollLeft;
1968                 y -= p.scrollTop;
1969             }
1970             p = p.parentNode;
1971         }
1972         return [x, y];
1973     },
1974  
1975   
1976
1977
1978     setXY : function(el, xy) {
1979         el = Roo.fly(el, '_setXY');
1980         el.position();
1981         var pts = el.translatePoints(xy);
1982         if (xy[0] !== false) {
1983             el.dom.style.left = pts.left + "px";
1984         }
1985         if (xy[1] !== false) {
1986             el.dom.style.top = pts.top + "px";
1987         }
1988     },
1989
1990     setX : function(el, x) {
1991         this.setXY(el, [x, false]);
1992     },
1993
1994     setY : function(el, y) {
1995         this.setXY(el, [false, y]);
1996     }
1997 };
1998 /*
1999  * Portions of this file are based on pieces of Yahoo User Interface Library
2000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001  * YUI licensed under the BSD License:
2002  * http://developer.yahoo.net/yui/license.txt
2003  * <script type="text/javascript">
2004  *
2005  */
2006
2007 Roo.lib.Event = function() {
2008     var loadComplete = false;
2009     var listeners = [];
2010     var unloadListeners = [];
2011     var retryCount = 0;
2012     var onAvailStack = [];
2013     var counter = 0;
2014     var lastError = null;
2015
2016     return {
2017         POLL_RETRYS: 200,
2018         POLL_INTERVAL: 20,
2019         EL: 0,
2020         TYPE: 1,
2021         FN: 2,
2022         WFN: 3,
2023         OBJ: 3,
2024         ADJ_SCOPE: 4,
2025         _interval: null,
2026
2027         startInterval: function() {
2028             if (!this._interval) {
2029                 var self = this;
2030                 var callback = function() {
2031                     self._tryPreloadAttach();
2032                 };
2033                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2034
2035             }
2036         },
2037
2038         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039             onAvailStack.push({ id:         p_id,
2040                 fn:         p_fn,
2041                 obj:        p_obj,
2042                 override:   p_override,
2043                 checkReady: false    });
2044
2045             retryCount = this.POLL_RETRYS;
2046             this.startInterval();
2047         },
2048
2049
2050         addListener: function(el, eventName, fn) {
2051             el = Roo.getDom(el);
2052             if (!el || !fn) {
2053                 return false;
2054             }
2055
2056             if ("unload" == eventName) {
2057                 unloadListeners[unloadListeners.length] =
2058                 [el, eventName, fn];
2059                 return true;
2060             }
2061
2062             var wrappedFn = function(e) {
2063                 return fn(Roo.lib.Event.getEvent(e));
2064             };
2065
2066             var li = [el, eventName, fn, wrappedFn];
2067
2068             var index = listeners.length;
2069             listeners[index] = li;
2070
2071             this.doAdd(el, eventName, wrappedFn, false);
2072             return true;
2073
2074         },
2075
2076
2077         removeListener: function(el, eventName, fn) {
2078             var i, len;
2079
2080             el = Roo.getDom(el);
2081
2082             if(!fn) {
2083                 return this.purgeElement(el, false, eventName);
2084             }
2085
2086
2087             if ("unload" == eventName) {
2088
2089                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090                     var li = unloadListeners[i];
2091                     if (li &&
2092                         li[0] == el &&
2093                         li[1] == eventName &&
2094                         li[2] == fn) {
2095                         unloadListeners.splice(i, 1);
2096                         return true;
2097                     }
2098                 }
2099
2100                 return false;
2101             }
2102
2103             var cacheItem = null;
2104
2105
2106             var index = arguments[3];
2107
2108             if ("undefined" == typeof index) {
2109                 index = this._getCacheIndex(el, eventName, fn);
2110             }
2111
2112             if (index >= 0) {
2113                 cacheItem = listeners[index];
2114             }
2115
2116             if (!el || !cacheItem) {
2117                 return false;
2118             }
2119
2120             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2121
2122             delete listeners[index][this.WFN];
2123             delete listeners[index][this.FN];
2124             listeners.splice(index, 1);
2125
2126             return true;
2127
2128         },
2129
2130
2131         getTarget: function(ev, resolveTextNode) {
2132             ev = ev.browserEvent || ev;
2133             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2134             var t = ev.target || ev.srcElement;
2135             return this.resolveTextNode(t);
2136         },
2137
2138
2139         resolveTextNode: function(node) {
2140             if (Roo.isSafari && node && 3 == node.nodeType) {
2141                 return node.parentNode;
2142             } else {
2143                 return node;
2144             }
2145         },
2146
2147
2148         getPageX: function(ev) {
2149             ev = ev.browserEvent || ev;
2150             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2151             var x = ev.pageX;
2152             if (!x && 0 !== x) {
2153                 x = ev.clientX || 0;
2154
2155                 if (Roo.isIE) {
2156                     x += this.getScroll()[1];
2157                 }
2158             }
2159
2160             return x;
2161         },
2162
2163
2164         getPageY: function(ev) {
2165             ev = ev.browserEvent || ev;
2166             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2167             var y = ev.pageY;
2168             if (!y && 0 !== y) {
2169                 y = ev.clientY || 0;
2170
2171                 if (Roo.isIE) {
2172                     y += this.getScroll()[0];
2173                 }
2174             }
2175
2176
2177             return y;
2178         },
2179
2180
2181         getXY: function(ev) {
2182             ev = ev.browserEvent || ev;
2183             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2184             return [this.getPageX(ev), this.getPageY(ev)];
2185         },
2186
2187
2188         getRelatedTarget: function(ev) {
2189             ev = ev.browserEvent || ev;
2190             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2191             var t = ev.relatedTarget;
2192             if (!t) {
2193                 if (ev.type == "mouseout") {
2194                     t = ev.toElement;
2195                 } else if (ev.type == "mouseover") {
2196                     t = ev.fromElement;
2197                 }
2198             }
2199
2200             return this.resolveTextNode(t);
2201         },
2202
2203
2204         getTime: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2207             if (!ev.time) {
2208                 var t = new Date().getTime();
2209                 try {
2210                     ev.time = t;
2211                 } catch(ex) {
2212                     this.lastError = ex;
2213                     return t;
2214                 }
2215             }
2216
2217             return ev.time;
2218         },
2219
2220
2221         stopEvent: function(ev) {
2222             this.stopPropagation(ev);
2223             this.preventDefault(ev);
2224         },
2225
2226
2227         stopPropagation: function(ev) {
2228             ev = ev.browserEvent || ev;
2229             if (ev.stopPropagation) {
2230                 ev.stopPropagation();
2231             } else {
2232                 ev.cancelBubble = true;
2233             }
2234         },
2235
2236
2237         preventDefault: function(ev) {
2238             ev = ev.browserEvent || ev;
2239             if(ev.preventDefault) {
2240                 ev.preventDefault();
2241             } else {
2242                 ev.returnValue = false;
2243             }
2244         },
2245
2246
2247         getEvent: function(e) {
2248             var ev = e || window.event;
2249             if (!ev) {
2250                 var c = this.getEvent.caller;
2251                 while (c) {
2252                     ev = c.arguments[0];
2253                     if (ev && Event == ev.constructor) {
2254                         break;
2255                     }
2256                     c = c.caller;
2257                 }
2258             }
2259             return ev;
2260         },
2261
2262
2263         getCharCode: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             return ev.charCode || ev.keyCode || 0;
2266         },
2267
2268
2269         _getCacheIndex: function(el, eventName, fn) {
2270             for (var i = 0,len = listeners.length; i < len; ++i) {
2271                 var li = listeners[i];
2272                 if (li &&
2273                     li[this.FN] == fn &&
2274                     li[this.EL] == el &&
2275                     li[this.TYPE] == eventName) {
2276                     return i;
2277                 }
2278             }
2279
2280             return -1;
2281         },
2282
2283
2284         elCache: {},
2285
2286
2287         getEl: function(id) {
2288             return document.getElementById(id);
2289         },
2290
2291
2292         clearCache: function() {
2293         },
2294
2295
2296         _load: function(e) {
2297             loadComplete = true;
2298             var EU = Roo.lib.Event;
2299
2300
2301             if (Roo.isIE) {
2302                 EU.doRemove(window, "load", EU._load);
2303             }
2304         },
2305
2306
2307         _tryPreloadAttach: function() {
2308
2309             if (this.locked) {
2310                 return false;
2311             }
2312
2313             this.locked = true;
2314
2315
2316             var tryAgain = !loadComplete;
2317             if (!tryAgain) {
2318                 tryAgain = (retryCount > 0);
2319             }
2320
2321
2322             var notAvail = [];
2323             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324                 var item = onAvailStack[i];
2325                 if (item) {
2326                     var el = this.getEl(item.id);
2327
2328                     if (el) {
2329                         if (!item.checkReady ||
2330                             loadComplete ||
2331                             el.nextSibling ||
2332                             (document && document.body)) {
2333
2334                             var scope = el;
2335                             if (item.override) {
2336                                 if (item.override === true) {
2337                                     scope = item.obj;
2338                                 } else {
2339                                     scope = item.override;
2340                                 }
2341                             }
2342                             item.fn.call(scope, item.obj);
2343                             onAvailStack[i] = null;
2344                         }
2345                     } else {
2346                         notAvail.push(item);
2347                     }
2348                 }
2349             }
2350
2351             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2352
2353             if (tryAgain) {
2354
2355                 this.startInterval();
2356             } else {
2357                 clearInterval(this._interval);
2358                 this._interval = null;
2359             }
2360
2361             this.locked = false;
2362
2363             return true;
2364
2365         },
2366
2367
2368         purgeElement: function(el, recurse, eventName) {
2369             var elListeners = this.getListeners(el, eventName);
2370             if (elListeners) {
2371                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372                     var l = elListeners[i];
2373                     this.removeListener(el, l.type, l.fn);
2374                 }
2375             }
2376
2377             if (recurse && el && el.childNodes) {
2378                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379                     this.purgeElement(el.childNodes[i], recurse, eventName);
2380                 }
2381             }
2382         },
2383
2384
2385         getListeners: function(el, eventName) {
2386             var results = [], searchLists;
2387             if (!eventName) {
2388                 searchLists = [listeners, unloadListeners];
2389             } else if (eventName == "unload") {
2390                 searchLists = [unloadListeners];
2391             } else {
2392                 searchLists = [listeners];
2393             }
2394
2395             for (var j = 0; j < searchLists.length; ++j) {
2396                 var searchList = searchLists[j];
2397                 if (searchList && searchList.length > 0) {
2398                     for (var i = 0,len = searchList.length; i < len; ++i) {
2399                         var l = searchList[i];
2400                         if (l && l[this.EL] === el &&
2401                             (!eventName || eventName === l[this.TYPE])) {
2402                             results.push({
2403                                 type:   l[this.TYPE],
2404                                 fn:     l[this.FN],
2405                                 obj:    l[this.OBJ],
2406                                 adjust: l[this.ADJ_SCOPE],
2407                                 index:  i
2408                             });
2409                         }
2410                     }
2411                 }
2412             }
2413
2414             return (results.length) ? results : null;
2415         },
2416
2417
2418         _unload: function(e) {
2419
2420             var EU = Roo.lib.Event, i, j, l, len, index;
2421
2422             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423                 l = unloadListeners[i];
2424                 if (l) {
2425                     var scope = window;
2426                     if (l[EU.ADJ_SCOPE]) {
2427                         if (l[EU.ADJ_SCOPE] === true) {
2428                             scope = l[EU.OBJ];
2429                         } else {
2430                             scope = l[EU.ADJ_SCOPE];
2431                         }
2432                     }
2433                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434                     unloadListeners[i] = null;
2435                     l = null;
2436                     scope = null;
2437                 }
2438             }
2439
2440             unloadListeners = null;
2441
2442             if (listeners && listeners.length > 0) {
2443                 j = listeners.length;
2444                 while (j) {
2445                     index = j - 1;
2446                     l = listeners[index];
2447                     if (l) {
2448                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2449                                 l[EU.FN], index);
2450                     }
2451                     j = j - 1;
2452                 }
2453                 l = null;
2454
2455                 EU.clearCache();
2456             }
2457
2458             EU.doRemove(window, "unload", EU._unload);
2459
2460         },
2461
2462
2463         getScroll: function() {
2464             var dd = document.documentElement, db = document.body;
2465             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466                 return [dd.scrollTop, dd.scrollLeft];
2467             } else if (db) {
2468                 return [db.scrollTop, db.scrollLeft];
2469             } else {
2470                 return [0, 0];
2471             }
2472         },
2473
2474
2475         doAdd: function () {
2476             if (window.addEventListener) {
2477                 return function(el, eventName, fn, capture) {
2478                     el.addEventListener(eventName, fn, (capture));
2479                 };
2480             } else if (window.attachEvent) {
2481                 return function(el, eventName, fn, capture) {
2482                     el.attachEvent("on" + eventName, fn);
2483                 };
2484             } else {
2485                 return function() {
2486                 };
2487             }
2488         }(),
2489
2490
2491         doRemove: function() {
2492             if (window.removeEventListener) {
2493                 return function (el, eventName, fn, capture) {
2494                     el.removeEventListener(eventName, fn, (capture));
2495                 };
2496             } else if (window.detachEvent) {
2497                 return function (el, eventName, fn) {
2498                     el.detachEvent("on" + eventName, fn);
2499                 };
2500             } else {
2501                 return function() {
2502                 };
2503             }
2504         }()
2505     };
2506     
2507 }();
2508 (function() {     
2509    
2510     var E = Roo.lib.Event;
2511     E.on = E.addListener;
2512     E.un = E.removeListener;
2513
2514     if (document && document.body) {
2515         E._load();
2516     } else {
2517         E.doAdd(window, "load", E._load);
2518     }
2519     E.doAdd(window, "unload", E._unload);
2520     E._tryPreloadAttach();
2521 })();
2522
2523 /*
2524  * Portions of this file are based on pieces of Yahoo User Interface Library
2525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526  * YUI licensed under the BSD License:
2527  * http://developer.yahoo.net/yui/license.txt
2528  * <script type="text/javascript">
2529  *
2530  */
2531
2532 (function() {
2533     /**
2534      * @class Roo.lib.Ajax
2535      *
2536      */
2537     Roo.lib.Ajax = {
2538         /**
2539          * @static 
2540          */
2541         request : function(method, uri, cb, data, options) {
2542             if(options){
2543                 var hs = options.headers;
2544                 if(hs){
2545                     for(var h in hs){
2546                         if(hs.hasOwnProperty(h)){
2547                             this.initHeader(h, hs[h], false);
2548                         }
2549                     }
2550                 }
2551                 if(options.xmlData){
2552                     this.initHeader('Content-Type', 'text/xml', false);
2553                     method = 'POST';
2554                     data = options.xmlData;
2555                 }
2556             }
2557
2558             return this.asyncRequest(method, uri, cb, data);
2559         },
2560
2561         serializeForm : function(form) {
2562             if(typeof form == 'string') {
2563                 form = (document.getElementById(form) || document.forms[form]);
2564             }
2565
2566             var el, name, val, disabled, data = '', hasSubmit = false;
2567             for (var i = 0; i < form.elements.length; i++) {
2568                 el = form.elements[i];
2569                 disabled = form.elements[i].disabled;
2570                 name = form.elements[i].name;
2571                 val = form.elements[i].value;
2572
2573                 if (!disabled && name){
2574                     switch (el.type)
2575                             {
2576                         case 'select-one':
2577                         case 'select-multiple':
2578                             for (var j = 0; j < el.options.length; j++) {
2579                                 if (el.options[j].selected) {
2580                                     if (Roo.isIE) {
2581                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2582                                     }
2583                                     else {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                 }
2587                             }
2588                             break;
2589                         case 'radio':
2590                         case 'checkbox':
2591                             if (el.checked) {
2592                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593                             }
2594                             break;
2595                         case 'file':
2596
2597                         case undefined:
2598
2599                         case 'reset':
2600
2601                         case 'button':
2602
2603                             break;
2604                         case 'submit':
2605                             if(hasSubmit == false) {
2606                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607                                 hasSubmit = true;
2608                             }
2609                             break;
2610                         default:
2611                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2612                             break;
2613                     }
2614                 }
2615             }
2616             data = data.substr(0, data.length - 1);
2617             return data;
2618         },
2619
2620         headers:{},
2621
2622         hasHeaders:false,
2623
2624         useDefaultHeader:true,
2625
2626         defaultPostHeader:'application/x-www-form-urlencoded',
2627
2628         useDefaultXhrHeader:true,
2629
2630         defaultXhrHeader:'XMLHttpRequest',
2631
2632         hasDefaultHeaders:true,
2633
2634         defaultHeaders:{},
2635
2636         poll:{},
2637
2638         timeout:{},
2639
2640         pollInterval:50,
2641
2642         transactionId:0,
2643
2644         setProgId:function(id)
2645         {
2646             this.activeX.unshift(id);
2647         },
2648
2649         setDefaultPostHeader:function(b)
2650         {
2651             this.useDefaultHeader = b;
2652         },
2653
2654         setDefaultXhrHeader:function(b)
2655         {
2656             this.useDefaultXhrHeader = b;
2657         },
2658
2659         setPollingInterval:function(i)
2660         {
2661             if (typeof i == 'number' && isFinite(i)) {
2662                 this.pollInterval = i;
2663             }
2664         },
2665
2666         createXhrObject:function(transactionId)
2667         {
2668             var obj,http;
2669             try
2670             {
2671
2672                 http = new XMLHttpRequest();
2673
2674                 obj = { conn:http, tId:transactionId };
2675             }
2676             catch(e)
2677             {
2678                 for (var i = 0; i < this.activeX.length; ++i) {
2679                     try
2680                     {
2681
2682                         http = new ActiveXObject(this.activeX[i]);
2683
2684                         obj = { conn:http, tId:transactionId };
2685                         break;
2686                     }
2687                     catch(e) {
2688                     }
2689                 }
2690             }
2691             finally
2692             {
2693                 return obj;
2694             }
2695         },
2696
2697         getConnectionObject:function()
2698         {
2699             var o;
2700             var tId = this.transactionId;
2701
2702             try
2703             {
2704                 o = this.createXhrObject(tId);
2705                 if (o) {
2706                     this.transactionId++;
2707                 }
2708             }
2709             catch(e) {
2710             }
2711             finally
2712             {
2713                 return o;
2714             }
2715         },
2716
2717         asyncRequest:function(method, uri, callback, postData)
2718         {
2719             var o = this.getConnectionObject();
2720
2721             if (!o) {
2722                 return null;
2723             }
2724             else {
2725                 o.conn.open(method, uri, true);
2726
2727                 if (this.useDefaultXhrHeader) {
2728                     if (!this.defaultHeaders['X-Requested-With']) {
2729                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2730                     }
2731                 }
2732
2733                 if(postData && this.useDefaultHeader){
2734                     this.initHeader('Content-Type', this.defaultPostHeader);
2735                 }
2736
2737                  if (this.hasDefaultHeaders || this.hasHeaders) {
2738                     this.setHeader(o);
2739                 }
2740
2741                 this.handleReadyState(o, callback);
2742                 o.conn.send(postData || null);
2743
2744                 return o;
2745             }
2746         },
2747
2748         handleReadyState:function(o, callback)
2749         {
2750             var oConn = this;
2751
2752             if (callback && callback.timeout) {
2753                 
2754                 this.timeout[o.tId] = window.setTimeout(function() {
2755                     oConn.abort(o, callback, true);
2756                 }, callback.timeout);
2757             }
2758
2759             this.poll[o.tId] = window.setInterval(
2760                     function() {
2761                         if (o.conn && o.conn.readyState == 4) {
2762                             window.clearInterval(oConn.poll[o.tId]);
2763                             delete oConn.poll[o.tId];
2764
2765                             if(callback && callback.timeout) {
2766                                 window.clearTimeout(oConn.timeout[o.tId]);
2767                                 delete oConn.timeout[o.tId];
2768                             }
2769
2770                             oConn.handleTransactionResponse(o, callback);
2771                         }
2772                     }
2773                     , this.pollInterval);
2774         },
2775
2776         handleTransactionResponse:function(o, callback, isAbort)
2777         {
2778
2779             if (!callback) {
2780                 this.releaseObject(o);
2781                 return;
2782             }
2783
2784             var httpStatus, responseObject;
2785
2786             try
2787             {
2788                 if (o.conn.status !== undefined && o.conn.status != 0) {
2789                     httpStatus = o.conn.status;
2790                 }
2791                 else {
2792                     httpStatus = 13030;
2793                 }
2794             }
2795             catch(e) {
2796
2797
2798                 httpStatus = 13030;
2799             }
2800
2801             if (httpStatus >= 200 && httpStatus < 300) {
2802                 responseObject = this.createResponseObject(o, callback.argument);
2803                 if (callback.success) {
2804                     if (!callback.scope) {
2805                         callback.success(responseObject);
2806                     }
2807                     else {
2808
2809
2810                         callback.success.apply(callback.scope, [responseObject]);
2811                     }
2812                 }
2813             }
2814             else {
2815                 switch (httpStatus) {
2816
2817                     case 12002:
2818                     case 12029:
2819                     case 12030:
2820                     case 12031:
2821                     case 12152:
2822                     case 13030:
2823                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824                         if (callback.failure) {
2825                             if (!callback.scope) {
2826                                 callback.failure(responseObject);
2827                             }
2828                             else {
2829                                 callback.failure.apply(callback.scope, [responseObject]);
2830                             }
2831                         }
2832                         break;
2833                     default:
2834                         responseObject = this.createResponseObject(o, callback.argument);
2835                         if (callback.failure) {
2836                             if (!callback.scope) {
2837                                 callback.failure(responseObject);
2838                             }
2839                             else {
2840                                 callback.failure.apply(callback.scope, [responseObject]);
2841                             }
2842                         }
2843                 }
2844             }
2845
2846             this.releaseObject(o);
2847             responseObject = null;
2848         },
2849
2850         createResponseObject:function(o, callbackArg)
2851         {
2852             var obj = {};
2853             var headerObj = {};
2854
2855             try
2856             {
2857                 var headerStr = o.conn.getAllResponseHeaders();
2858                 var header = headerStr.split('\n');
2859                 for (var i = 0; i < header.length; i++) {
2860                     var delimitPos = header[i].indexOf(':');
2861                     if (delimitPos != -1) {
2862                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863                     }
2864                 }
2865             }
2866             catch(e) {
2867             }
2868
2869             obj.tId = o.tId;
2870             obj.status = o.conn.status;
2871             obj.statusText = o.conn.statusText;
2872             obj.getResponseHeader = headerObj;
2873             obj.getAllResponseHeaders = headerStr;
2874             obj.responseText = o.conn.responseText;
2875             obj.responseXML = o.conn.responseXML;
2876
2877             if (typeof callbackArg !== undefined) {
2878                 obj.argument = callbackArg;
2879             }
2880
2881             return obj;
2882         },
2883
2884         createExceptionObject:function(tId, callbackArg, isAbort)
2885         {
2886             var COMM_CODE = 0;
2887             var COMM_ERROR = 'communication failure';
2888             var ABORT_CODE = -1;
2889             var ABORT_ERROR = 'transaction aborted';
2890
2891             var obj = {};
2892
2893             obj.tId = tId;
2894             if (isAbort) {
2895                 obj.status = ABORT_CODE;
2896                 obj.statusText = ABORT_ERROR;
2897             }
2898             else {
2899                 obj.status = COMM_CODE;
2900                 obj.statusText = COMM_ERROR;
2901             }
2902
2903             if (callbackArg) {
2904                 obj.argument = callbackArg;
2905             }
2906
2907             return obj;
2908         },
2909
2910         initHeader:function(label, value, isDefault)
2911         {
2912             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2913
2914             if (headerObj[label] === undefined) {
2915                 headerObj[label] = value;
2916             }
2917             else {
2918
2919
2920                 headerObj[label] = value + "," + headerObj[label];
2921             }
2922
2923             if (isDefault) {
2924                 this.hasDefaultHeaders = true;
2925             }
2926             else {
2927                 this.hasHeaders = true;
2928             }
2929         },
2930
2931
2932         setHeader:function(o)
2933         {
2934             if (this.hasDefaultHeaders) {
2935                 for (var prop in this.defaultHeaders) {
2936                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2937                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2938                     }
2939                 }
2940             }
2941
2942             if (this.hasHeaders) {
2943                 for (var prop in this.headers) {
2944                     if (this.headers.hasOwnProperty(prop)) {
2945                         o.conn.setRequestHeader(prop, this.headers[prop]);
2946                     }
2947                 }
2948                 this.headers = {};
2949                 this.hasHeaders = false;
2950             }
2951         },
2952
2953         resetDefaultHeaders:function() {
2954             delete this.defaultHeaders;
2955             this.defaultHeaders = {};
2956             this.hasDefaultHeaders = false;
2957         },
2958
2959         abort:function(o, callback, isTimeout)
2960         {
2961             if(this.isCallInProgress(o)) {
2962                 o.conn.abort();
2963                 window.clearInterval(this.poll[o.tId]);
2964                 delete this.poll[o.tId];
2965                 if (isTimeout) {
2966                     delete this.timeout[o.tId];
2967                 }
2968
2969                 this.handleTransactionResponse(o, callback, true);
2970
2971                 return true;
2972             }
2973             else {
2974                 return false;
2975             }
2976         },
2977
2978
2979         isCallInProgress:function(o)
2980         {
2981             if (o && o.conn) {
2982                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2983             }
2984             else {
2985
2986                 return false;
2987             }
2988         },
2989
2990
2991         releaseObject:function(o)
2992         {
2993
2994             o.conn = null;
2995
2996             o = null;
2997         },
2998
2999         activeX:[
3000         'MSXML2.XMLHTTP.3.0',
3001         'MSXML2.XMLHTTP',
3002         'Microsoft.XMLHTTP'
3003         ]
3004
3005
3006     };
3007 })();/*
3008  * Portions of this file are based on pieces of Yahoo User Interface Library
3009  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010  * YUI licensed under the BSD License:
3011  * http://developer.yahoo.net/yui/license.txt
3012  * <script type="text/javascript">
3013  *
3014  */
3015
3016 Roo.lib.Region = function(t, r, b, l) {
3017     this.top = t;
3018     this[1] = t;
3019     this.right = r;
3020     this.bottom = b;
3021     this.left = l;
3022     this[0] = l;
3023 };
3024
3025
3026 Roo.lib.Region.prototype = {
3027     contains : function(region) {
3028         return ( region.left >= this.left &&
3029                  region.right <= this.right &&
3030                  region.top >= this.top &&
3031                  region.bottom <= this.bottom    );
3032
3033     },
3034
3035     getArea : function() {
3036         return ( (this.bottom - this.top) * (this.right - this.left) );
3037     },
3038
3039     intersect : function(region) {
3040         var t = Math.max(this.top, region.top);
3041         var r = Math.min(this.right, region.right);
3042         var b = Math.min(this.bottom, region.bottom);
3043         var l = Math.max(this.left, region.left);
3044
3045         if (b >= t && r >= l) {
3046             return new Roo.lib.Region(t, r, b, l);
3047         } else {
3048             return null;
3049         }
3050     },
3051     union : function(region) {
3052         var t = Math.min(this.top, region.top);
3053         var r = Math.max(this.right, region.right);
3054         var b = Math.max(this.bottom, region.bottom);
3055         var l = Math.min(this.left, region.left);
3056
3057         return new Roo.lib.Region(t, r, b, l);
3058     },
3059
3060     adjust : function(t, l, b, r) {
3061         this.top += t;
3062         this.left += l;
3063         this.right += r;
3064         this.bottom += b;
3065         return this;
3066     }
3067 };
3068
3069 Roo.lib.Region.getRegion = function(el) {
3070     var p = Roo.lib.Dom.getXY(el);
3071
3072     var t = p[1];
3073     var r = p[0] + el.offsetWidth;
3074     var b = p[1] + el.offsetHeight;
3075     var l = p[0];
3076
3077     return new Roo.lib.Region(t, r, b, l);
3078 };
3079 /*
3080  * Portions of this file are based on pieces of Yahoo User Interface Library
3081  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082  * YUI licensed under the BSD License:
3083  * http://developer.yahoo.net/yui/license.txt
3084  * <script type="text/javascript">
3085  *
3086  */
3087 //@@dep Roo.lib.Region
3088
3089
3090 Roo.lib.Point = function(x, y) {
3091     if (x instanceof Array) {
3092         y = x[1];
3093         x = x[0];
3094     }
3095     this.x = this.right = this.left = this[0] = x;
3096     this.y = this.top = this.bottom = this[1] = y;
3097 };
3098
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3100 /*
3101  * Portions of this file are based on pieces of Yahoo User Interface Library
3102  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103  * YUI licensed under the BSD License:
3104  * http://developer.yahoo.net/yui/license.txt
3105  * <script type="text/javascript">
3106  *
3107  */
3108  
3109 (function() {   
3110
3111     Roo.lib.Anim = {
3112         scroll : function(el, args, duration, easing, cb, scope) {
3113             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3114         },
3115
3116         motion : function(el, args, duration, easing, cb, scope) {
3117             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3118         },
3119
3120         color : function(el, args, duration, easing, cb, scope) {
3121             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3122         },
3123
3124         run : function(el, args, duration, easing, cb, scope, type) {
3125             type = type || Roo.lib.AnimBase;
3126             if (typeof easing == "string") {
3127                 easing = Roo.lib.Easing[easing];
3128             }
3129             var anim = new type(el, args, duration, easing);
3130             anim.animateX(function() {
3131                 Roo.callback(cb, scope);
3132             });
3133             return anim;
3134         }
3135     };
3136 })();/*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144
3145 (function() {    
3146     var libFlyweight;
3147     
3148     function fly(el) {
3149         if (!libFlyweight) {
3150             libFlyweight = new Roo.Element.Flyweight();
3151         }
3152         libFlyweight.dom = el;
3153         return libFlyweight;
3154     }
3155
3156     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3157     
3158    
3159     
3160     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3161         if (el) {
3162             this.init(el, attributes, duration, method);
3163         }
3164     };
3165
3166     Roo.lib.AnimBase.fly = fly;
3167     
3168     
3169     
3170     Roo.lib.AnimBase.prototype = {
3171
3172         toString: function() {
3173             var el = this.getEl();
3174             var id = el.id || el.tagName;
3175             return ("Anim " + id);
3176         },
3177
3178         patterns: {
3179             noNegatives:        /width|height|opacity|padding/i,
3180             offsetAttribute:  /^((width|height)|(top|left))$/,
3181             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3182             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3183         },
3184
3185
3186         doMethod: function(attr, start, end) {
3187             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3188         },
3189
3190
3191         setAttribute: function(attr, val, unit) {
3192             if (this.patterns.noNegatives.test(attr)) {
3193                 val = (val > 0) ? val : 0;
3194             }
3195
3196             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3197         },
3198
3199
3200         getAttribute: function(attr) {
3201             var el = this.getEl();
3202             var val = fly(el).getStyle(attr);
3203
3204             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205                 return parseFloat(val);
3206             }
3207
3208             var a = this.patterns.offsetAttribute.exec(attr) || [];
3209             var pos = !!( a[3] );
3210             var box = !!( a[2] );
3211
3212
3213             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3215             } else {
3216                 val = 0;
3217             }
3218
3219             return val;
3220         },
3221
3222
3223         getDefaultUnit: function(attr) {
3224             if (this.patterns.defaultUnit.test(attr)) {
3225                 return 'px';
3226             }
3227
3228             return '';
3229         },
3230
3231         animateX : function(callback, scope) {
3232             var f = function() {
3233                 this.onComplete.removeListener(f);
3234                 if (typeof callback == "function") {
3235                     callback.call(scope || this, this);
3236                 }
3237             };
3238             this.onComplete.addListener(f, this);
3239             this.animate();
3240         },
3241
3242
3243         setRuntimeAttribute: function(attr) {
3244             var start;
3245             var end;
3246             var attributes = this.attributes;
3247
3248             this.runtimeAttributes[attr] = {};
3249
3250             var isset = function(prop) {
3251                 return (typeof prop !== 'undefined');
3252             };
3253
3254             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3255                 return false;
3256             }
3257
3258             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3259
3260
3261             if (isset(attributes[attr]['to'])) {
3262                 end = attributes[attr]['to'];
3263             } else if (isset(attributes[attr]['by'])) {
3264                 if (start.constructor == Array) {
3265                     end = [];
3266                     for (var i = 0, len = start.length; i < len; ++i) {
3267                         end[i] = start[i] + attributes[attr]['by'][i];
3268                     }
3269                 } else {
3270                     end = start + attributes[attr]['by'];
3271                 }
3272             }
3273
3274             this.runtimeAttributes[attr].start = start;
3275             this.runtimeAttributes[attr].end = end;
3276
3277
3278             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3279         },
3280
3281
3282         init: function(el, attributes, duration, method) {
3283
3284             var isAnimated = false;
3285
3286
3287             var startTime = null;
3288
3289
3290             var actualFrames = 0;
3291
3292
3293             el = Roo.getDom(el);
3294
3295
3296             this.attributes = attributes || {};
3297
3298
3299             this.duration = duration || 1;
3300
3301
3302             this.method = method || Roo.lib.Easing.easeNone;
3303
3304
3305             this.useSeconds = true;
3306
3307
3308             this.currentFrame = 0;
3309
3310
3311             this.totalFrames = Roo.lib.AnimMgr.fps;
3312
3313
3314             this.getEl = function() {
3315                 return el;
3316             };
3317
3318
3319             this.isAnimated = function() {
3320                 return isAnimated;
3321             };
3322
3323
3324             this.getStartTime = function() {
3325                 return startTime;
3326             };
3327
3328             this.runtimeAttributes = {};
3329
3330
3331             this.animate = function() {
3332                 if (this.isAnimated()) {
3333                     return false;
3334                 }
3335
3336                 this.currentFrame = 0;
3337
3338                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3339
3340                 Roo.lib.AnimMgr.registerElement(this);
3341             };
3342
3343
3344             this.stop = function(finish) {
3345                 if (finish) {
3346                     this.currentFrame = this.totalFrames;
3347                     this._onTween.fire();
3348                 }
3349                 Roo.lib.AnimMgr.stop(this);
3350             };
3351
3352             var onStart = function() {
3353                 this.onStart.fire();
3354
3355                 this.runtimeAttributes = {};
3356                 for (var attr in this.attributes) {
3357                     this.setRuntimeAttribute(attr);
3358                 }
3359
3360                 isAnimated = true;
3361                 actualFrames = 0;
3362                 startTime = new Date();
3363             };
3364
3365
3366             var onTween = function() {
3367                 var data = {
3368                     duration: new Date() - this.getStartTime(),
3369                     currentFrame: this.currentFrame
3370                 };
3371
3372                 data.toString = function() {
3373                     return (
3374                             'duration: ' + data.duration +
3375                             ', currentFrame: ' + data.currentFrame
3376                             );
3377                 };
3378
3379                 this.onTween.fire(data);
3380
3381                 var runtimeAttributes = this.runtimeAttributes;
3382
3383                 for (var attr in runtimeAttributes) {
3384                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3385                 }
3386
3387                 actualFrames += 1;
3388             };
3389
3390             var onComplete = function() {
3391                 var actual_duration = (new Date() - startTime) / 1000 ;
3392
3393                 var data = {
3394                     duration: actual_duration,
3395                     frames: actualFrames,
3396                     fps: actualFrames / actual_duration
3397                 };
3398
3399                 data.toString = function() {
3400                     return (
3401                             'duration: ' + data.duration +
3402                             ', frames: ' + data.frames +
3403                             ', fps: ' + data.fps
3404                             );
3405                 };
3406
3407                 isAnimated = false;
3408                 actualFrames = 0;
3409                 this.onComplete.fire(data);
3410             };
3411
3412
3413             this._onStart = new Roo.util.Event(this);
3414             this.onStart = new Roo.util.Event(this);
3415             this.onTween = new Roo.util.Event(this);
3416             this._onTween = new Roo.util.Event(this);
3417             this.onComplete = new Roo.util.Event(this);
3418             this._onComplete = new Roo.util.Event(this);
3419             this._onStart.addListener(onStart);
3420             this._onTween.addListener(onTween);
3421             this._onComplete.addListener(onComplete);
3422         }
3423     };
3424 })();
3425 /*
3426  * Portions of this file are based on pieces of Yahoo User Interface Library
3427  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428  * YUI licensed under the BSD License:
3429  * http://developer.yahoo.net/yui/license.txt
3430  * <script type="text/javascript">
3431  *
3432  */
3433
3434 Roo.lib.AnimMgr = new function() {
3435
3436     var thread = null;
3437
3438
3439     var queue = [];
3440
3441
3442     var tweenCount = 0;
3443
3444
3445     this.fps = 1000;
3446
3447
3448     this.delay = 1;
3449
3450
3451     this.registerElement = function(tween) {
3452         queue[queue.length] = tween;
3453         tweenCount += 1;
3454         tween._onStart.fire();
3455         this.start();
3456     };
3457
3458
3459     this.unRegister = function(tween, index) {
3460         tween._onComplete.fire();
3461         index = index || getIndex(tween);
3462         if (index != -1) {
3463             queue.splice(index, 1);
3464         }
3465
3466         tweenCount -= 1;
3467         if (tweenCount <= 0) {
3468             this.stop();
3469         }
3470     };
3471
3472
3473     this.start = function() {
3474         if (thread === null) {
3475             thread = setInterval(this.run, this.delay);
3476         }
3477     };
3478
3479
3480     this.stop = function(tween) {
3481         if (!tween) {
3482             clearInterval(thread);
3483
3484             for (var i = 0, len = queue.length; i < len; ++i) {
3485                 if (queue[0].isAnimated()) {
3486                     this.unRegister(queue[0], 0);
3487                 }
3488             }
3489
3490             queue = [];
3491             thread = null;
3492             tweenCount = 0;
3493         }
3494         else {
3495             this.unRegister(tween);
3496         }
3497     };
3498
3499
3500     this.run = function() {
3501         for (var i = 0, len = queue.length; i < len; ++i) {
3502             var tween = queue[i];
3503             if (!tween || !tween.isAnimated()) {
3504                 continue;
3505             }
3506
3507             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3508             {
3509                 tween.currentFrame += 1;
3510
3511                 if (tween.useSeconds) {
3512                     correctFrame(tween);
3513                 }
3514                 tween._onTween.fire();
3515             }
3516             else {
3517                 Roo.lib.AnimMgr.stop(tween, i);
3518             }
3519         }
3520     };
3521
3522     var getIndex = function(anim) {
3523         for (var i = 0, len = queue.length; i < len; ++i) {
3524             if (queue[i] == anim) {
3525                 return i;
3526             }
3527         }
3528         return -1;
3529     };
3530
3531
3532     var correctFrame = function(tween) {
3533         var frames = tween.totalFrames;
3534         var frame = tween.currentFrame;
3535         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536         var elapsed = (new Date() - tween.getStartTime());
3537         var tweak = 0;
3538
3539         if (elapsed < tween.duration * 1000) {
3540             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3541         } else {
3542             tweak = frames - (frame + 1);
3543         }
3544         if (tweak > 0 && isFinite(tweak)) {
3545             if (tween.currentFrame + tweak >= frames) {
3546                 tweak = frames - (frame + 1);
3547             }
3548
3549             tween.currentFrame += tweak;
3550         }
3551     };
3552 };
3553
3554     /*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 Roo.lib.Bezier = new function() {
3563
3564         this.getPosition = function(points, t) {
3565             var n = points.length;
3566             var tmp = [];
3567
3568             for (var i = 0; i < n; ++i) {
3569                 tmp[i] = [points[i][0], points[i][1]];
3570             }
3571
3572             for (var j = 1; j < n; ++j) {
3573                 for (i = 0; i < n - j; ++i) {
3574                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3576                 }
3577             }
3578
3579             return [ tmp[0][0], tmp[0][1] ];
3580
3581         };
3582     };/*
3583  * Portions of this file are based on pieces of Yahoo User Interface Library
3584  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585  * YUI licensed under the BSD License:
3586  * http://developer.yahoo.net/yui/license.txt
3587  * <script type="text/javascript">
3588  *
3589  */
3590 (function() {
3591
3592     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3594     };
3595
3596     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3597
3598     var fly = Roo.lib.AnimBase.fly;
3599     var Y = Roo.lib;
3600     var superclass = Y.ColorAnim.superclass;
3601     var proto = Y.ColorAnim.prototype;
3602
3603     proto.toString = function() {
3604         var el = this.getEl();
3605         var id = el.id || el.tagName;
3606         return ("ColorAnim " + id);
3607     };
3608
3609     proto.patterns.color = /color$/i;
3610     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3614
3615
3616     proto.parseColor = function(s) {
3617         if (s.length == 3) {
3618             return s;
3619         }
3620
3621         var c = this.patterns.hex.exec(s);
3622         if (c && c.length == 4) {
3623             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3624         }
3625
3626         c = this.patterns.rgb.exec(s);
3627         if (c && c.length == 4) {
3628             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3629         }
3630
3631         c = this.patterns.hex3.exec(s);
3632         if (c && c.length == 4) {
3633             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3634         }
3635
3636         return null;
3637     };
3638     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639     proto.getAttribute = function(attr) {
3640         var el = this.getEl();
3641         if (this.patterns.color.test(attr)) {
3642             var val = fly(el).getStyle(attr);
3643
3644             if (this.patterns.transparent.test(val)) {
3645                 var parent = el.parentNode;
3646                 val = fly(parent).getStyle(attr);
3647
3648                 while (parent && this.patterns.transparent.test(val)) {
3649                     parent = parent.parentNode;
3650                     val = fly(parent).getStyle(attr);
3651                     if (parent.tagName.toUpperCase() == 'HTML') {
3652                         val = '#fff';
3653                     }
3654                 }
3655             }
3656         } else {
3657             val = superclass.getAttribute.call(this, attr);
3658         }
3659
3660         return val;
3661     };
3662     proto.getAttribute = function(attr) {
3663         var el = this.getEl();
3664         if (this.patterns.color.test(attr)) {
3665             var val = fly(el).getStyle(attr);
3666
3667             if (this.patterns.transparent.test(val)) {
3668                 var parent = el.parentNode;
3669                 val = fly(parent).getStyle(attr);
3670
3671                 while (parent && this.patterns.transparent.test(val)) {
3672                     parent = parent.parentNode;
3673                     val = fly(parent).getStyle(attr);
3674                     if (parent.tagName.toUpperCase() == 'HTML') {
3675                         val = '#fff';
3676                     }
3677                 }
3678             }
3679         } else {
3680             val = superclass.getAttribute.call(this, attr);
3681         }
3682
3683         return val;
3684     };
3685
3686     proto.doMethod = function(attr, start, end) {
3687         var val;
3688
3689         if (this.patterns.color.test(attr)) {
3690             val = [];
3691             for (var i = 0, len = start.length; i < len; ++i) {
3692                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3693             }
3694
3695             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3696         }
3697         else {
3698             val = superclass.doMethod.call(this, attr, start, end);
3699         }
3700
3701         return val;
3702     };
3703
3704     proto.setRuntimeAttribute = function(attr) {
3705         superclass.setRuntimeAttribute.call(this, attr);
3706
3707         if (this.patterns.color.test(attr)) {
3708             var attributes = this.attributes;
3709             var start = this.parseColor(this.runtimeAttributes[attr].start);
3710             var end = this.parseColor(this.runtimeAttributes[attr].end);
3711
3712             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713                 end = this.parseColor(attributes[attr].by);
3714
3715                 for (var i = 0, len = start.length; i < len; ++i) {
3716                     end[i] = start[i] + end[i];
3717                 }
3718             }
3719
3720             this.runtimeAttributes[attr].start = start;
3721             this.runtimeAttributes[attr].end = end;
3722         }
3723     };
3724 })();
3725
3726 /*
3727  * Portions of this file are based on pieces of Yahoo User Interface Library
3728  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729  * YUI licensed under the BSD License:
3730  * http://developer.yahoo.net/yui/license.txt
3731  * <script type="text/javascript">
3732  *
3733  */
3734 Roo.lib.Easing = {
3735
3736
3737     easeNone: function (t, b, c, d) {
3738         return c * t / d + b;
3739     },
3740
3741
3742     easeIn: function (t, b, c, d) {
3743         return c * (t /= d) * t + b;
3744     },
3745
3746
3747     easeOut: function (t, b, c, d) {
3748         return -c * (t /= d) * (t - 2) + b;
3749     },
3750
3751
3752     easeBoth: function (t, b, c, d) {
3753         if ((t /= d / 2) < 1) {
3754             return c / 2 * t * t + b;
3755         }
3756
3757         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3758     },
3759
3760
3761     easeInStrong: function (t, b, c, d) {
3762         return c * (t /= d) * t * t * t + b;
3763     },
3764
3765
3766     easeOutStrong: function (t, b, c, d) {
3767         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3768     },
3769
3770
3771     easeBothStrong: function (t, b, c, d) {
3772         if ((t /= d / 2) < 1) {
3773             return c / 2 * t * t * t * t + b;
3774         }
3775
3776         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3777     },
3778
3779
3780
3781     elasticIn: function (t, b, c, d, a, p) {
3782         if (t == 0) {
3783             return b;
3784         }
3785         if ((t /= d) == 1) {
3786             return b + c;
3787         }
3788         if (!p) {
3789             p = d * .3;
3790         }
3791
3792         if (!a || a < Math.abs(c)) {
3793             a = c;
3794             var s = p / 4;
3795         }
3796         else {
3797             var s = p / (2 * Math.PI) * Math.asin(c / a);
3798         }
3799
3800         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3801     },
3802
3803
3804     elasticOut: function (t, b, c, d, a, p) {
3805         if (t == 0) {
3806             return b;
3807         }
3808         if ((t /= d) == 1) {
3809             return b + c;
3810         }
3811         if (!p) {
3812             p = d * .3;
3813         }
3814
3815         if (!a || a < Math.abs(c)) {
3816             a = c;
3817             var s = p / 4;
3818         }
3819         else {
3820             var s = p / (2 * Math.PI) * Math.asin(c / a);
3821         }
3822
3823         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3824     },
3825
3826
3827     elasticBoth: function (t, b, c, d, a, p) {
3828         if (t == 0) {
3829             return b;
3830         }
3831
3832         if ((t /= d / 2) == 2) {
3833             return b + c;
3834         }
3835
3836         if (!p) {
3837             p = d * (.3 * 1.5);
3838         }
3839
3840         if (!a || a < Math.abs(c)) {
3841             a = c;
3842             var s = p / 4;
3843         }
3844         else {
3845             var s = p / (2 * Math.PI) * Math.asin(c / a);
3846         }
3847
3848         if (t < 1) {
3849             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3851         }
3852         return a * Math.pow(2, -10 * (t -= 1)) *
3853                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3854     },
3855
3856
3857
3858     backIn: function (t, b, c, d, s) {
3859         if (typeof s == 'undefined') {
3860             s = 1.70158;
3861         }
3862         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3863     },
3864
3865
3866     backOut: function (t, b, c, d, s) {
3867         if (typeof s == 'undefined') {
3868             s = 1.70158;
3869         }
3870         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3871     },
3872
3873
3874     backBoth: function (t, b, c, d, s) {
3875         if (typeof s == 'undefined') {
3876             s = 1.70158;
3877         }
3878
3879         if ((t /= d / 2 ) < 1) {
3880             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3881         }
3882         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3883     },
3884
3885
3886     bounceIn: function (t, b, c, d) {
3887         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3888     },
3889
3890
3891     bounceOut: function (t, b, c, d) {
3892         if ((t /= d) < (1 / 2.75)) {
3893             return c * (7.5625 * t * t) + b;
3894         } else if (t < (2 / 2.75)) {
3895             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896         } else if (t < (2.5 / 2.75)) {
3897             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3898         }
3899         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3900     },
3901
3902
3903     bounceBoth: function (t, b, c, d) {
3904         if (t < d / 2) {
3905             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3906         }
3907         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3908     }
3909 };/*
3910  * Portions of this file are based on pieces of Yahoo User Interface Library
3911  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912  * YUI licensed under the BSD License:
3913  * http://developer.yahoo.net/yui/license.txt
3914  * <script type="text/javascript">
3915  *
3916  */
3917     (function() {
3918         Roo.lib.Motion = function(el, attributes, duration, method) {
3919             if (el) {
3920                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3921             }
3922         };
3923
3924         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3925
3926
3927         var Y = Roo.lib;
3928         var superclass = Y.Motion.superclass;
3929         var proto = Y.Motion.prototype;
3930
3931         proto.toString = function() {
3932             var el = this.getEl();
3933             var id = el.id || el.tagName;
3934             return ("Motion " + id);
3935         };
3936
3937         proto.patterns.points = /^points$/i;
3938
3939         proto.setAttribute = function(attr, val, unit) {
3940             if (this.patterns.points.test(attr)) {
3941                 unit = unit || 'px';
3942                 superclass.setAttribute.call(this, 'left', val[0], unit);
3943                 superclass.setAttribute.call(this, 'top', val[1], unit);
3944             } else {
3945                 superclass.setAttribute.call(this, attr, val, unit);
3946             }
3947         };
3948
3949         proto.getAttribute = function(attr) {
3950             if (this.patterns.points.test(attr)) {
3951                 var val = [
3952                         superclass.getAttribute.call(this, 'left'),
3953                         superclass.getAttribute.call(this, 'top')
3954                         ];
3955             } else {
3956                 val = superclass.getAttribute.call(this, attr);
3957             }
3958
3959             return val;
3960         };
3961
3962         proto.doMethod = function(attr, start, end) {
3963             var val = null;
3964
3965             if (this.patterns.points.test(attr)) {
3966                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3968             } else {
3969                 val = superclass.doMethod.call(this, attr, start, end);
3970             }
3971             return val;
3972         };
3973
3974         proto.setRuntimeAttribute = function(attr) {
3975             if (this.patterns.points.test(attr)) {
3976                 var el = this.getEl();
3977                 var attributes = this.attributes;
3978                 var start;
3979                 var control = attributes['points']['control'] || [];
3980                 var end;
3981                 var i, len;
3982
3983                 if (control.length > 0 && !(control[0] instanceof Array)) {
3984                     control = [control];
3985                 } else {
3986                     var tmp = [];
3987                     for (i = 0,len = control.length; i < len; ++i) {
3988                         tmp[i] = control[i];
3989                     }
3990                     control = tmp;
3991                 }
3992
3993                 Roo.fly(el).position();
3994
3995                 if (isset(attributes['points']['from'])) {
3996                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3997                 }
3998                 else {
3999                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4000                 }
4001
4002                 start = this.getAttribute('points');
4003
4004
4005                 if (isset(attributes['points']['to'])) {
4006                     end = translateValues.call(this, attributes['points']['to'], start);
4007
4008                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009                     for (i = 0,len = control.length; i < len; ++i) {
4010                         control[i] = translateValues.call(this, control[i], start);
4011                     }
4012
4013
4014                 } else if (isset(attributes['points']['by'])) {
4015                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4016
4017                     for (i = 0,len = control.length; i < len; ++i) {
4018                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4019                     }
4020                 }
4021
4022                 this.runtimeAttributes[attr] = [start];
4023
4024                 if (control.length > 0) {
4025                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4026                 }
4027
4028                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4029             }
4030             else {
4031                 superclass.setRuntimeAttribute.call(this, attr);
4032             }
4033         };
4034
4035         var translateValues = function(val, start) {
4036             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4038
4039             return val;
4040         };
4041
4042         var isset = function(prop) {
4043             return (typeof prop !== 'undefined');
4044         };
4045     })();
4046 /*
4047  * Portions of this file are based on pieces of Yahoo User Interface Library
4048  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049  * YUI licensed under the BSD License:
4050  * http://developer.yahoo.net/yui/license.txt
4051  * <script type="text/javascript">
4052  *
4053  */
4054     (function() {
4055         Roo.lib.Scroll = function(el, attributes, duration, method) {
4056             if (el) {
4057                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4058             }
4059         };
4060
4061         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4062
4063
4064         var Y = Roo.lib;
4065         var superclass = Y.Scroll.superclass;
4066         var proto = Y.Scroll.prototype;
4067
4068         proto.toString = function() {
4069             var el = this.getEl();
4070             var id = el.id || el.tagName;
4071             return ("Scroll " + id);
4072         };
4073
4074         proto.doMethod = function(attr, start, end) {
4075             var val = null;
4076
4077             if (attr == 'scroll') {
4078                 val = [
4079                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4081                         ];
4082
4083             } else {
4084                 val = superclass.doMethod.call(this, attr, start, end);
4085             }
4086             return val;
4087         };
4088
4089         proto.getAttribute = function(attr) {
4090             var val = null;
4091             var el = this.getEl();
4092
4093             if (attr == 'scroll') {
4094                 val = [ el.scrollLeft, el.scrollTop ];
4095             } else {
4096                 val = superclass.getAttribute.call(this, attr);
4097             }
4098
4099             return val;
4100         };
4101
4102         proto.setAttribute = function(attr, val, unit) {
4103             var el = this.getEl();
4104
4105             if (attr == 'scroll') {
4106                 el.scrollLeft = val[0];
4107                 el.scrollTop = val[1];
4108             } else {
4109                 superclass.setAttribute.call(this, attr, val, unit);
4110             }
4111         };
4112     })();
4113 /*
4114  * Based on:
4115  * Ext JS Library 1.1.1
4116  * Copyright(c) 2006-2007, Ext JS, LLC.
4117  *
4118  * Originally Released Under LGPL - original licence link has changed is not relivant.
4119  *
4120  * Fork - LGPL
4121  * <script type="text/javascript">
4122  */
4123
4124
4125 // nasty IE9 hack - what a pile of crap that is..
4126
4127  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128     Range.prototype.createContextualFragment = function (html) {
4129         var doc = window.document;
4130         var container = doc.createElement("div");
4131         container.innerHTML = html;
4132         var frag = doc.createDocumentFragment(), n;
4133         while ((n = container.firstChild)) {
4134             frag.appendChild(n);
4135         }
4136         return frag;
4137     };
4138 }
4139
4140 /**
4141  * @class Roo.DomHelper
4142  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4144  * @singleton
4145  */
4146 Roo.DomHelper = function(){
4147     var tempTableEl = null;
4148     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149     var tableRe = /^table|tbody|tr|td$/i;
4150     var xmlns = {};
4151     // build as innerHTML where available
4152     /** @ignore */
4153     var createHtml = function(o){
4154         if(typeof o == 'string'){
4155             return o;
4156         }
4157         var b = "";
4158         if(!o.tag){
4159             o.tag = "div";
4160         }
4161         b += "<" + o.tag;
4162         for(var attr in o){
4163             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164             if(attr == "style"){
4165                 var s = o["style"];
4166                 if(typeof s == "function"){
4167                     s = s.call();
4168                 }
4169                 if(typeof s == "string"){
4170                     b += ' style="' + s + '"';
4171                 }else if(typeof s == "object"){
4172                     b += ' style="';
4173                     for(var key in s){
4174                         if(typeof s[key] != "function"){
4175                             b += key + ":" + s[key] + ";";
4176                         }
4177                     }
4178                     b += '"';
4179                 }
4180             }else{
4181                 if(attr == "cls"){
4182                     b += ' class="' + o["cls"] + '"';
4183                 }else if(attr == "htmlFor"){
4184                     b += ' for="' + o["htmlFor"] + '"';
4185                 }else{
4186                     b += " " + attr + '="' + o[attr] + '"';
4187                 }
4188             }
4189         }
4190         if(emptyTags.test(o.tag)){
4191             b += "/>";
4192         }else{
4193             b += ">";
4194             var cn = o.children || o.cn;
4195             if(cn){
4196                 //http://bugs.kde.org/show_bug.cgi?id=71506
4197                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                     for(var i = 0, len = cn.length; i < len; i++) {
4199                         b += createHtml(cn[i], b);
4200                     }
4201                 }else{
4202                     b += createHtml(cn, b);
4203                 }
4204             }
4205             if(o.html){
4206                 b += o.html;
4207             }
4208             b += "</" + o.tag + ">";
4209         }
4210         return b;
4211     };
4212
4213     // build as dom
4214     /** @ignore */
4215     var createDom = function(o, parentNode){
4216          
4217         // defininition craeted..
4218         var ns = false;
4219         if (o.ns && o.ns != 'html') {
4220                
4221             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222                 xmlns[o.ns] = o.xmlns;
4223                 ns = o.xmlns;
4224             }
4225             if (typeof(xmlns[o.ns]) == 'undefined') {
4226                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4227             }
4228             ns = xmlns[o.ns];
4229         }
4230         
4231         
4232         if (typeof(o) == 'string') {
4233             return parentNode.appendChild(document.createTextNode(o));
4234         }
4235         o.tag = o.tag || div;
4236         if (o.ns && Roo.isIE) {
4237             ns = false;
4238             o.tag = o.ns + ':' + o.tag;
4239             
4240         }
4241         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4242         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4243         for(var attr in o){
4244             
4245             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4246                     attr == "style" || typeof o[attr] == "function") { continue; }
4247                     
4248             if(attr=="cls" && Roo.isIE){
4249                 el.className = o["cls"];
4250             }else{
4251                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4252                 else { 
4253                     el[attr] = o[attr];
4254                 }
4255             }
4256         }
4257         Roo.DomHelper.applyStyles(el, o.style);
4258         var cn = o.children || o.cn;
4259         if(cn){
4260             //http://bugs.kde.org/show_bug.cgi?id=71506
4261              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262                 for(var i = 0, len = cn.length; i < len; i++) {
4263                     createDom(cn[i], el);
4264                 }
4265             }else{
4266                 createDom(cn, el);
4267             }
4268         }
4269         if(o.html){
4270             el.innerHTML = o.html;
4271         }
4272         if(parentNode){
4273            parentNode.appendChild(el);
4274         }
4275         return el;
4276     };
4277
4278     var ieTable = function(depth, s, h, e){
4279         tempTableEl.innerHTML = [s, h, e].join('');
4280         var i = -1, el = tempTableEl;
4281         while(++i < depth){
4282             el = el.firstChild;
4283         }
4284         return el;
4285     };
4286
4287     // kill repeat to save bytes
4288     var ts = '<table>',
4289         te = '</table>',
4290         tbs = ts+'<tbody>',
4291         tbe = '</tbody>'+te,
4292         trs = tbs + '<tr>',
4293         tre = '</tr>'+tbe;
4294
4295     /**
4296      * @ignore
4297      * Nasty code for IE's broken table implementation
4298      */
4299     var insertIntoTable = function(tag, where, el, html){
4300         if(!tempTableEl){
4301             tempTableEl = document.createElement('div');
4302         }
4303         var node;
4304         var before = null;
4305         if(tag == 'td'){
4306             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4307                 return;
4308             }
4309             if(where == 'beforebegin'){
4310                 before = el;
4311                 el = el.parentNode;
4312             } else{
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315             }
4316             node = ieTable(4, trs, html, tre);
4317         }
4318         else if(tag == 'tr'){
4319             if(where == 'beforebegin'){
4320                 before = el;
4321                 el = el.parentNode;
4322                 node = ieTable(3, tbs, html, tbe);
4323             } else if(where == 'afterend'){
4324                 before = el.nextSibling;
4325                 el = el.parentNode;
4326                 node = ieTable(3, tbs, html, tbe);
4327             } else{ // INTO a TR
4328                 if(where == 'afterbegin'){
4329                     before = el.firstChild;
4330                 }
4331                 node = ieTable(4, trs, html, tre);
4332             }
4333         } else if(tag == 'tbody'){
4334             if(where == 'beforebegin'){
4335                 before = el;
4336                 el = el.parentNode;
4337                 node = ieTable(2, ts, html, te);
4338             } else if(where == 'afterend'){
4339                 before = el.nextSibling;
4340                 el = el.parentNode;
4341                 node = ieTable(2, ts, html, te);
4342             } else{
4343                 if(where == 'afterbegin'){
4344                     before = el.firstChild;
4345                 }
4346                 node = ieTable(3, tbs, html, tbe);
4347             }
4348         } else{ // TABLE
4349             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4350                 return;
4351             }
4352             if(where == 'afterbegin'){
4353                 before = el.firstChild;
4354             }
4355             node = ieTable(2, ts, html, te);
4356         }
4357         el.insertBefore(node, before);
4358         return node;
4359     };
4360
4361     return {
4362     /** True to force the use of DOM instead of html fragments @type Boolean */
4363     useDom : false,
4364
4365     /**
4366      * Returns the markup for the passed Element(s) config
4367      * @param {Object} o The Dom object spec (and children)
4368      * @return {String}
4369      */
4370     markup : function(o){
4371         return createHtml(o);
4372     },
4373
4374     /**
4375      * Applies a style specification to an element
4376      * @param {String/HTMLElement} el The element to apply styles to
4377      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378      * a function which returns such a specification.
4379      */
4380     applyStyles : function(el, styles){
4381         if(styles){
4382            el = Roo.fly(el);
4383            if(typeof styles == "string"){
4384                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4385                var matches;
4386                while ((matches = re.exec(styles)) != null){
4387                    el.setStyle(matches[1], matches[2]);
4388                }
4389            }else if (typeof styles == "object"){
4390                for (var style in styles){
4391                   el.setStyle(style, styles[style]);
4392                }
4393            }else if (typeof styles == "function"){
4394                 Roo.DomHelper.applyStyles(el, styles.call());
4395            }
4396         }
4397     },
4398
4399     /**
4400      * Inserts an HTML fragment into the Dom
4401      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402      * @param {HTMLElement} el The context element
4403      * @param {String} html The HTML fragmenet
4404      * @return {HTMLElement} The new node
4405      */
4406     insertHtml : function(where, el, html){
4407         where = where.toLowerCase();
4408         if(el.insertAdjacentHTML){
4409             if(tableRe.test(el.tagName)){
4410                 var rs;
4411                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4412                     return rs;
4413                 }
4414             }
4415             switch(where){
4416                 case "beforebegin":
4417                     el.insertAdjacentHTML('BeforeBegin', html);
4418                     return el.previousSibling;
4419                 case "afterbegin":
4420                     el.insertAdjacentHTML('AfterBegin', html);
4421                     return el.firstChild;
4422                 case "beforeend":
4423                     el.insertAdjacentHTML('BeforeEnd', html);
4424                     return el.lastChild;
4425                 case "afterend":
4426                     el.insertAdjacentHTML('AfterEnd', html);
4427                     return el.nextSibling;
4428             }
4429             throw 'Illegal insertion point -> "' + where + '"';
4430         }
4431         var range = el.ownerDocument.createRange();
4432         var frag;
4433         switch(where){
4434              case "beforebegin":
4435                 range.setStartBefore(el);
4436                 frag = range.createContextualFragment(html);
4437                 el.parentNode.insertBefore(frag, el);
4438                 return el.previousSibling;
4439              case "afterbegin":
4440                 if(el.firstChild){
4441                     range.setStartBefore(el.firstChild);
4442                     frag = range.createContextualFragment(html);
4443                     el.insertBefore(frag, el.firstChild);
4444                     return el.firstChild;
4445                 }else{
4446                     el.innerHTML = html;
4447                     return el.firstChild;
4448                 }
4449             case "beforeend":
4450                 if(el.lastChild){
4451                     range.setStartAfter(el.lastChild);
4452                     frag = range.createContextualFragment(html);
4453                     el.appendChild(frag);
4454                     return el.lastChild;
4455                 }else{
4456                     el.innerHTML = html;
4457                     return el.lastChild;
4458                 }
4459             case "afterend":
4460                 range.setStartAfter(el);
4461                 frag = range.createContextualFragment(html);
4462                 el.parentNode.insertBefore(frag, el.nextSibling);
4463                 return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them before el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertBefore : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "beforeBegin");
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and inserts them after el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object} o The Dom object spec (and children)
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     insertAfter : function(el, o, returnElement){
4487         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4488     },
4489
4490     /**
4491      * Creates new Dom element(s) and inserts them as the first child of el
4492      * @param {String/HTMLElement/Element} el The context element
4493      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495      * @return {HTMLElement/Roo.Element} The new node
4496      */
4497     insertFirst : function(el, o, returnElement){
4498         return this.doInsert(el, o, returnElement, "afterBegin");
4499     },
4500
4501     // private
4502     doInsert : function(el, o, returnElement, pos, sibling){
4503         el = Roo.getDom(el);
4504         var newNode;
4505         if(this.useDom || o.ns){
4506             newNode = createDom(o, null);
4507             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4508         }else{
4509             var html = createHtml(o);
4510             newNode = this.insertHtml(pos, el, html);
4511         }
4512         return returnElement ? Roo.get(newNode, true) : newNode;
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and appends them to el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     append : function(el, o, returnElement){
4523         el = Roo.getDom(el);
4524         var newNode;
4525         if(this.useDom || o.ns){
4526             newNode = createDom(o, null);
4527             el.appendChild(newNode);
4528         }else{
4529             var html = createHtml(o);
4530             newNode = this.insertHtml("beforeEnd", el, html);
4531         }
4532         return returnElement ? Roo.get(newNode, true) : newNode;
4533     },
4534
4535     /**
4536      * Creates new Dom element(s) and overwrites the contents of el with them
4537      * @param {String/HTMLElement/Element} el The context element
4538      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540      * @return {HTMLElement/Roo.Element} The new node
4541      */
4542     overwrite : function(el, o, returnElement){
4543         el = Roo.getDom(el);
4544         if (o.ns) {
4545           
4546             while (el.childNodes.length) {
4547                 el.removeChild(el.firstChild);
4548             }
4549             createDom(o, el);
4550         } else {
4551             el.innerHTML = createHtml(o);   
4552         }
4553         
4554         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4555     },
4556
4557     /**
4558      * Creates a new Roo.DomHelper.Template from the Dom object spec
4559      * @param {Object} o The Dom object spec (and children)
4560      * @return {Roo.DomHelper.Template} The new template
4561      */
4562     createTemplate : function(o){
4563         var html = createHtml(o);
4564         return new Roo.Template(html);
4565     }
4566     };
4567 }();
4568 /*
4569  * Based on:
4570  * Ext JS Library 1.1.1
4571  * Copyright(c) 2006-2007, Ext JS, LLC.
4572  *
4573  * Originally Released Under LGPL - original licence link has changed is not relivant.
4574  *
4575  * Fork - LGPL
4576  * <script type="text/javascript">
4577  */
4578  
4579 /**
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4583 * Usage:
4584 <pre><code>
4585 var t = new Roo.Template({
4586     html :  '&lt;div name="{id}"&gt;' + 
4587         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4588         '&lt;/div&gt;',
4589     myformat: function (value, allValues) {
4590         return 'XX' + value;
4591     }
4592 });
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4594 </code></pre>
4595 * For more information see this blog post with examples:
4596 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597      - Create Elements using DOM, HTML fragments and Templates</a>. 
4598 * @constructor
4599 * @param {Object} cfg - Configuration object.
4600 */
4601 Roo.Template = function(cfg){
4602     // BC!
4603     if(cfg instanceof Array){
4604         cfg = cfg.join("");
4605     }else if(arguments.length > 1){
4606         cfg = Array.prototype.join.call(arguments, "");
4607     }
4608     
4609     
4610     if (typeof(cfg) == 'object') {
4611         Roo.apply(this,cfg)
4612     } else {
4613         // bc
4614         this.html = cfg;
4615     }
4616     if (this.url) {
4617         this.load();
4618     }
4619     
4620 };
4621 Roo.Template.prototype = {
4622     
4623     /**
4624      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4625      *                    it should be fixed so that template is observable...
4626      */
4627     url : false,
4628     /**
4629      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4630      */
4631     html : '',
4632     /**
4633      * Returns an HTML fragment of this template with the specified values applied.
4634      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4635      * @return {String} The HTML fragment
4636      */
4637     applyTemplate : function(values){
4638         try {
4639            
4640             if(this.compiled){
4641                 return this.compiled(values);
4642             }
4643             var useF = this.disableFormats !== true;
4644             var fm = Roo.util.Format, tpl = this;
4645             var fn = function(m, name, format, args){
4646                 if(format && useF){
4647                     if(format.substr(0, 5) == "this."){
4648                         return tpl.call(format.substr(5), values[name], values);
4649                     }else{
4650                         if(args){
4651                             // quoted values are required for strings in compiled templates, 
4652                             // but for non compiled we need to strip them
4653                             // quoted reversed for jsmin
4654                             var re = /^\s*['"](.*)["']\s*$/;
4655                             args = args.split(',');
4656                             for(var i = 0, len = args.length; i < len; i++){
4657                                 args[i] = args[i].replace(re, "$1");
4658                             }
4659                             args = [values[name]].concat(args);
4660                         }else{
4661                             args = [values[name]];
4662                         }
4663                         return fm[format].apply(fm, args);
4664                     }
4665                 }else{
4666                     return values[name] !== undefined ? values[name] : "";
4667                 }
4668             };
4669             return this.html.replace(this.re, fn);
4670         } catch (e) {
4671             Roo.log(e);
4672             throw e;
4673         }
4674          
4675     },
4676     
4677     loading : false,
4678       
4679     load : function ()
4680     {
4681          
4682         if (this.loading) {
4683             return;
4684         }
4685         var _t = this;
4686         
4687         this.loading = true;
4688         this.compiled = false;
4689         
4690         var cx = new Roo.data.Connection();
4691         cx.request({
4692             url : this.url,
4693             method : 'GET',
4694             success : function (response) {
4695                 _t.loading = false;
4696                 _t.html = response.responseText;
4697                 _t.url = false;
4698                 _t.compile();
4699              },
4700             failure : function(response) {
4701                 Roo.log("Template failed to load from " + _t.url);
4702                 _t.loading = false;
4703             }
4704         });
4705     },
4706
4707     /**
4708      * Sets the HTML used as the template and optionally compiles it.
4709      * @param {String} html
4710      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711      * @return {Roo.Template} this
4712      */
4713     set : function(html, compile){
4714         this.html = html;
4715         this.compiled = null;
4716         if(compile){
4717             this.compile();
4718         }
4719         return this;
4720     },
4721     
4722     /**
4723      * True to disable format functions (defaults to false)
4724      * @type Boolean
4725      */
4726     disableFormats : false,
4727     
4728     /**
4729     * The regular expression used to match template variables 
4730     * @type RegExp
4731     * @property 
4732     */
4733     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4734     
4735     /**
4736      * Compiles the template into an internal function, eliminating the RegEx overhead.
4737      * @return {Roo.Template} this
4738      */
4739     compile : function(){
4740         var fm = Roo.util.Format;
4741         var useF = this.disableFormats !== true;
4742         var sep = Roo.isGecko ? "+" : ",";
4743         var fn = function(m, name, format, args){
4744             if(format && useF){
4745                 args = args ? ',' + args : "";
4746                 if(format.substr(0, 5) != "this."){
4747                     format = "fm." + format + '(';
4748                 }else{
4749                     format = 'this.call("'+ format.substr(5) + '", ';
4750                     args = ", values";
4751                 }
4752             }else{
4753                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4754             }
4755             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4756         };
4757         var body;
4758         // branched to use + in gecko and [].join() in others
4759         if(Roo.isGecko){
4760             body = "this.compiled = function(values){ return '" +
4761                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4762                     "';};";
4763         }else{
4764             body = ["this.compiled = function(values){ return ['"];
4765             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766             body.push("'].join('');};");
4767             body = body.join('');
4768         }
4769         /**
4770          * eval:var:values
4771          * eval:var:fm
4772          */
4773         eval(body);
4774         return this;
4775     },
4776     
4777     // private function used to call members
4778     call : function(fnName, value, allValues){
4779         return this[fnName](value, allValues);
4780     },
4781     
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertFirst: function(el, values, returnElement){
4790         return this.doInsert('afterBegin', el, values, returnElement);
4791     },
4792
4793     /**
4794      * Applies the supplied values to the template and inserts the new node(s) before el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     insertBefore: function(el, values, returnElement){
4801         return this.doInsert('beforeBegin', el, values, returnElement);
4802     },
4803
4804     /**
4805      * Applies the supplied values to the template and inserts the new node(s) after el.
4806      * @param {String/HTMLElement/Roo.Element} el The context element
4807      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4808      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809      * @return {HTMLElement/Roo.Element} The new node or Element
4810      */
4811     insertAfter : function(el, values, returnElement){
4812         return this.doInsert('afterEnd', el, values, returnElement);
4813     },
4814     
4815     /**
4816      * Applies the supplied values to the template and appends the new node(s) to el.
4817      * @param {String/HTMLElement/Roo.Element} el The context element
4818      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4819      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820      * @return {HTMLElement/Roo.Element} The new node or Element
4821      */
4822     append : function(el, values, returnElement){
4823         return this.doInsert('beforeEnd', el, values, returnElement);
4824     },
4825
4826     doInsert : function(where, el, values, returnEl){
4827         el = Roo.getDom(el);
4828         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829         return returnEl ? Roo.get(newNode, true) : newNode;
4830     },
4831
4832     /**
4833      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834      * @param {String/HTMLElement/Roo.Element} el The context element
4835      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4836      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837      * @return {HTMLElement/Roo.Element} The new node or Element
4838      */
4839     overwrite : function(el, values, returnElement){
4840         el = Roo.getDom(el);
4841         el.innerHTML = this.applyTemplate(values);
4842         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4843     }
4844 };
4845 /**
4846  * Alias for {@link #applyTemplate}
4847  * @method
4848  */
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4850
4851 // backwards compat
4852 Roo.DomHelper.Template = Roo.Template;
4853
4854 /**
4855  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856  * @param {String/HTMLElement} el A DOM element or its id
4857  * @returns {Roo.Template} The created template
4858  * @static
4859  */
4860 Roo.Template.from = function(el){
4861     el = Roo.getDom(el);
4862     return new Roo.Template(el.value || el.innerHTML);
4863 };/*
4864  * Based on:
4865  * Ext JS Library 1.1.1
4866  * Copyright(c) 2006-2007, Ext JS, LLC.
4867  *
4868  * Originally Released Under LGPL - original licence link has changed is not relivant.
4869  *
4870  * Fork - LGPL
4871  * <script type="text/javascript">
4872  */
4873  
4874
4875 /*
4876  * This is code is also distributed under MIT license for use
4877  * with jQuery and prototype JavaScript libraries.
4878  */
4879 /**
4880  * @class Roo.DomQuery
4881 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4882 <p>
4883 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4884
4885 <p>
4886 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4887 </p>
4888 <h4>Element Selectors:</h4>
4889 <ul class="list">
4890     <li> <b>*</b> any element</li>
4891     <li> <b>E</b> an element with the tag E</li>
4892     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4896 </ul>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4899 <ul class="list">
4900     <li> <b>E[foo]</b> has an attribute "foo"</li>
4901     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4907 </ul>
4908 <h4>Pseudo Classes:</h4>
4909 <ul class="list">
4910     <li> <b>E:first-child</b> E is the first child of its parent</li>
4911     <li> <b>E:last-child</b> E is the last child of its parent</li>
4912     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4913     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915     <li> <b>E:only-child</b> E is the only child of its parent</li>
4916     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4917     <li> <b>E:first</b> the first E in the resultset</li>
4918     <li> <b>E:last</b> the last E in the resultset</li>
4919     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4928 </ul>
4929 <h4>CSS Value Selectors:</h4>
4930 <ul class="list">
4931     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4937 </ul>
4938  * @singleton
4939  */
4940 Roo.DomQuery = function(){
4941     var cache = {}, simpleCache = {}, valueCache = {};
4942     var nonSpace = /\S/;
4943     var trimRe = /^\s+|\s+$/g;
4944     var tplRe = /\{(\d+)\}/g;
4945     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946     var tagTokenRe = /^(#)?([\w-\*]+)/;
4947     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4948
4949     function child(p, index){
4950         var i = 0;
4951         var n = p.firstChild;
4952         while(n){
4953             if(n.nodeType == 1){
4954                if(++i == index){
4955                    return n;
4956                }
4957             }
4958             n = n.nextSibling;
4959         }
4960         return null;
4961     };
4962
4963     function next(n){
4964         while((n = n.nextSibling) && n.nodeType != 1);
4965         return n;
4966     };
4967
4968     function prev(n){
4969         while((n = n.previousSibling) && n.nodeType != 1);
4970         return n;
4971     };
4972
4973     function children(d){
4974         var n = d.firstChild, ni = -1;
4975             while(n){
4976                 var nx = n.nextSibling;
4977                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978                     d.removeChild(n);
4979                 }else{
4980                     n.nodeIndex = ++ni;
4981                 }
4982                 n = nx;
4983             }
4984             return this;
4985         };
4986
4987     function byClassName(c, a, v){
4988         if(!v){
4989             return c;
4990         }
4991         var r = [], ri = -1, cn;
4992         for(var i = 0, ci; ci = c[i]; i++){
4993             if((' '+ci.className+' ').indexOf(v) != -1){
4994                 r[++ri] = ci;
4995             }
4996         }
4997         return r;
4998     };
4999
5000     function attrValue(n, attr){
5001         if(!n.tagName && typeof n.length != "undefined"){
5002             n = n[0];
5003         }
5004         if(!n){
5005             return null;
5006         }
5007         if(attr == "for"){
5008             return n.htmlFor;
5009         }
5010         if(attr == "class" || attr == "className"){
5011             return n.className;
5012         }
5013         return n.getAttribute(attr) || n[attr];
5014
5015     };
5016
5017     function getNodes(ns, mode, tagName){
5018         var result = [], ri = -1, cs;
5019         if(!ns){
5020             return result;
5021         }
5022         tagName = tagName || "*";
5023         if(typeof ns.getElementsByTagName != "undefined"){
5024             ns = [ns];
5025         }
5026         if(!mode){
5027             for(var i = 0, ni; ni = ns[i]; i++){
5028                 cs = ni.getElementsByTagName(tagName);
5029                 for(var j = 0, ci; ci = cs[j]; j++){
5030                     result[++ri] = ci;
5031                 }
5032             }
5033         }else if(mode == "/" || mode == ">"){
5034             var utag = tagName.toUpperCase();
5035             for(var i = 0, ni, cn; ni = ns[i]; i++){
5036                 cn = ni.children || ni.childNodes;
5037                 for(var j = 0, cj; cj = cn[j]; j++){
5038                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5039                         result[++ri] = cj;
5040                     }
5041                 }
5042             }
5043         }else if(mode == "+"){
5044             var utag = tagName.toUpperCase();
5045             for(var i = 0, n; n = ns[i]; i++){
5046                 while((n = n.nextSibling) && n.nodeType != 1);
5047                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5048                     result[++ri] = n;
5049                 }
5050             }
5051         }else if(mode == "~"){
5052             for(var i = 0, n; n = ns[i]; i++){
5053                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5054                 if(n){
5055                     result[++ri] = n;
5056                 }
5057             }
5058         }
5059         return result;
5060     };
5061
5062     function concat(a, b){
5063         if(b.slice){
5064             return a.concat(b);
5065         }
5066         for(var i = 0, l = b.length; i < l; i++){
5067             a[a.length] = b[i];
5068         }
5069         return a;
5070     }
5071
5072     function byTag(cs, tagName){
5073         if(cs.tagName || cs == document){
5074             cs = [cs];
5075         }
5076         if(!tagName){
5077             return cs;
5078         }
5079         var r = [], ri = -1;
5080         tagName = tagName.toLowerCase();
5081         for(var i = 0, ci; ci = cs[i]; i++){
5082             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5083                 r[++ri] = ci;
5084             }
5085         }
5086         return r;
5087     };
5088
5089     function byId(cs, attr, id){
5090         if(cs.tagName || cs == document){
5091             cs = [cs];
5092         }
5093         if(!id){
5094             return cs;
5095         }
5096         var r = [], ri = -1;
5097         for(var i = 0,ci; ci = cs[i]; i++){
5098             if(ci && ci.id == id){
5099                 r[++ri] = ci;
5100                 return r;
5101             }
5102         }
5103         return r;
5104     };
5105
5106     function byAttribute(cs, attr, value, op, custom){
5107         var r = [], ri = -1, st = custom=="{";
5108         var f = Roo.DomQuery.operators[op];
5109         for(var i = 0, ci; ci = cs[i]; i++){
5110             var a;
5111             if(st){
5112                 a = Roo.DomQuery.getStyle(ci, attr);
5113             }
5114             else if(attr == "class" || attr == "className"){
5115                 a = ci.className;
5116             }else if(attr == "for"){
5117                 a = ci.htmlFor;
5118             }else if(attr == "href"){
5119                 a = ci.getAttribute("href", 2);
5120             }else{
5121                 a = ci.getAttribute(attr);
5122             }
5123             if((f && f(a, value)) || (!f && a)){
5124                 r[++ri] = ci;
5125             }
5126         }
5127         return r;
5128     };
5129
5130     function byPseudo(cs, name, value){
5131         return Roo.DomQuery.pseudos[name](cs, value);
5132     };
5133
5134     // This is for IE MSXML which does not support expandos.
5135     // IE runs the same speed using setAttribute, however FF slows way down
5136     // and Safari completely fails so they need to continue to use expandos.
5137     var isIE = window.ActiveXObject ? true : false;
5138
5139     // this eval is stop the compressor from
5140     // renaming the variable to something shorter
5141     
5142     /** eval:var:batch */
5143     var batch = 30803; 
5144
5145     var key = 30803;
5146
5147     function nodupIEXml(cs){
5148         var d = ++key;
5149         cs[0].setAttribute("_nodup", d);
5150         var r = [cs[0]];
5151         for(var i = 1, len = cs.length; i < len; i++){
5152             var c = cs[i];
5153             if(!c.getAttribute("_nodup") != d){
5154                 c.setAttribute("_nodup", d);
5155                 r[r.length] = c;
5156             }
5157         }
5158         for(var i = 0, len = cs.length; i < len; i++){
5159             cs[i].removeAttribute("_nodup");
5160         }
5161         return r;
5162     }
5163
5164     function nodup(cs){
5165         if(!cs){
5166             return [];
5167         }
5168         var len = cs.length, c, i, r = cs, cj, ri = -1;
5169         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5170             return cs;
5171         }
5172         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173             return nodupIEXml(cs);
5174         }
5175         var d = ++key;
5176         cs[0]._nodup = d;
5177         for(i = 1; c = cs[i]; i++){
5178             if(c._nodup != d){
5179                 c._nodup = d;
5180             }else{
5181                 r = [];
5182                 for(var j = 0; j < i; j++){
5183                     r[++ri] = cs[j];
5184                 }
5185                 for(j = i+1; cj = cs[j]; j++){
5186                     if(cj._nodup != d){
5187                         cj._nodup = d;
5188                         r[++ri] = cj;
5189                     }
5190                 }
5191                 return r;
5192             }
5193         }
5194         return r;
5195     }
5196
5197     function quickDiffIEXml(c1, c2){
5198         var d = ++key;
5199         for(var i = 0, len = c1.length; i < len; i++){
5200             c1[i].setAttribute("_qdiff", d);
5201         }
5202         var r = [];
5203         for(var i = 0, len = c2.length; i < len; i++){
5204             if(c2[i].getAttribute("_qdiff") != d){
5205                 r[r.length] = c2[i];
5206             }
5207         }
5208         for(var i = 0, len = c1.length; i < len; i++){
5209            c1[i].removeAttribute("_qdiff");
5210         }
5211         return r;
5212     }
5213
5214     function quickDiff(c1, c2){
5215         var len1 = c1.length;
5216         if(!len1){
5217             return c2;
5218         }
5219         if(isIE && c1[0].selectSingleNode){
5220             return quickDiffIEXml(c1, c2);
5221         }
5222         var d = ++key;
5223         for(var i = 0; i < len1; i++){
5224             c1[i]._qdiff = d;
5225         }
5226         var r = [];
5227         for(var i = 0, len = c2.length; i < len; i++){
5228             if(c2[i]._qdiff != d){
5229                 r[r.length] = c2[i];
5230             }
5231         }
5232         return r;
5233     }
5234
5235     function quickId(ns, mode, root, id){
5236         if(ns == root){
5237            var d = root.ownerDocument || root;
5238            return d.getElementById(id);
5239         }
5240         ns = getNodes(ns, mode, "*");
5241         return byId(ns, null, id);
5242     }
5243
5244     return {
5245         getStyle : function(el, name){
5246             return Roo.fly(el).getStyle(name);
5247         },
5248         /**
5249          * Compiles a selector/xpath query into a reusable function. The returned function
5250          * takes one parameter "root" (optional), which is the context node from where the query should start.
5251          * @param {String} selector The selector/xpath query
5252          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253          * @return {Function}
5254          */
5255         compile : function(path, type){
5256             type = type || "select";
5257             
5258             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259             var q = path, mode, lq;
5260             var tk = Roo.DomQuery.matchers;
5261             var tklen = tk.length;
5262             var mm;
5263
5264             // accept leading mode switch
5265             var lmode = q.match(modeRe);
5266             if(lmode && lmode[1]){
5267                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268                 q = q.replace(lmode[1], "");
5269             }
5270             // strip leading slashes
5271             while(path.substr(0, 1)=="/"){
5272                 path = path.substr(1);
5273             }
5274
5275             while(q && lq != q){
5276                 lq = q;
5277                 var tm = q.match(tagTokenRe);
5278                 if(type == "select"){
5279                     if(tm){
5280                         if(tm[1] == "#"){
5281                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5282                         }else{
5283                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5284                         }
5285                         q = q.replace(tm[0], "");
5286                     }else if(q.substr(0, 1) != '@'){
5287                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5288                     }
5289                 }else{
5290                     if(tm){
5291                         if(tm[1] == "#"){
5292                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5293                         }else{
5294                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5295                         }
5296                         q = q.replace(tm[0], "");
5297                     }
5298                 }
5299                 while(!(mm = q.match(modeRe))){
5300                     var matched = false;
5301                     for(var j = 0; j < tklen; j++){
5302                         var t = tk[j];
5303                         var m = q.match(t.re);
5304                         if(m){
5305                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5306                                                     return m[i];
5307                                                 });
5308                             q = q.replace(m[0], "");
5309                             matched = true;
5310                             break;
5311                         }
5312                     }
5313                     // prevent infinite loop on bad selector
5314                     if(!matched){
5315                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5316                     }
5317                 }
5318                 if(mm[1]){
5319                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320                     q = q.replace(mm[1], "");
5321                 }
5322             }
5323             fn[fn.length] = "return nodup(n);\n}";
5324             
5325              /** 
5326               * list of variables that need from compression as they are used by eval.
5327              *  eval:var:batch 
5328              *  eval:var:nodup
5329              *  eval:var:byTag
5330              *  eval:var:ById
5331              *  eval:var:getNodes
5332              *  eval:var:quickId
5333              *  eval:var:mode
5334              *  eval:var:root
5335              *  eval:var:n
5336              *  eval:var:byClassName
5337              *  eval:var:byPseudo
5338              *  eval:var:byAttribute
5339              *  eval:var:attrValue
5340              * 
5341              **/ 
5342             eval(fn.join(""));
5343             return f;
5344         },
5345
5346         /**
5347          * Selects a group of elements.
5348          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349          * @param {Node} root (optional) The start of the query (defaults to document).
5350          * @return {Array}
5351          */
5352         select : function(path, root, type){
5353             if(!root || root == document){
5354                 root = document;
5355             }
5356             if(typeof root == "string"){
5357                 root = document.getElementById(root);
5358             }
5359             var paths = path.split(",");
5360             var results = [];
5361             for(var i = 0, len = paths.length; i < len; i++){
5362                 var p = paths[i].replace(trimRe, "");
5363                 if(!cache[p]){
5364                     cache[p] = Roo.DomQuery.compile(p);
5365                     if(!cache[p]){
5366                         throw p + " is not a valid selector";
5367                     }
5368                 }
5369                 var result = cache[p](root);
5370                 if(result && result != document){
5371                     results = results.concat(result);
5372                 }
5373             }
5374             if(paths.length > 1){
5375                 return nodup(results);
5376             }
5377             return results;
5378         },
5379
5380         /**
5381          * Selects a single element.
5382          * @param {String} selector The selector/xpath query
5383          * @param {Node} root (optional) The start of the query (defaults to document).
5384          * @return {Element}
5385          */
5386         selectNode : function(path, root){
5387             return Roo.DomQuery.select(path, root)[0];
5388         },
5389
5390         /**
5391          * Selects the value of a node, optionally replacing null with the defaultValue.
5392          * @param {String} selector The selector/xpath query
5393          * @param {Node} root (optional) The start of the query (defaults to document).
5394          * @param {String} defaultValue
5395          */
5396         selectValue : function(path, root, defaultValue){
5397             path = path.replace(trimRe, "");
5398             if(!valueCache[path]){
5399                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5400             }
5401             var n = valueCache[path](root);
5402             n = n[0] ? n[0] : n;
5403             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5405         },
5406
5407         /**
5408          * Selects the value of a node, parsing integers and floats.
5409          * @param {String} selector The selector/xpath query
5410          * @param {Node} root (optional) The start of the query (defaults to document).
5411          * @param {Number} defaultValue
5412          * @return {Number}
5413          */
5414         selectNumber : function(path, root, defaultValue){
5415             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416             return parseFloat(v);
5417         },
5418
5419         /**
5420          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422          * @param {String} selector The simple selector to test
5423          * @return {Boolean}
5424          */
5425         is : function(el, ss){
5426             if(typeof el == "string"){
5427                 el = document.getElementById(el);
5428             }
5429             var isArray = (el instanceof Array);
5430             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431             return isArray ? (result.length == el.length) : (result.length > 0);
5432         },
5433
5434         /**
5435          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436          * @param {Array} el An array of elements to filter
5437          * @param {String} selector The simple selector to test
5438          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439          * the selector instead of the ones that match
5440          * @return {Array}
5441          */
5442         filter : function(els, ss, nonMatches){
5443             ss = ss.replace(trimRe, "");
5444             if(!simpleCache[ss]){
5445                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5446             }
5447             var result = simpleCache[ss](els);
5448             return nonMatches ? quickDiff(result, els) : result;
5449         },
5450
5451         /**
5452          * Collection of matching regular expressions and code snippets.
5453          */
5454         matchers : [{
5455                 re: /^\.([\w-]+)/,
5456                 select: 'n = byClassName(n, null, " {1} ");'
5457             }, {
5458                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459                 select: 'n = byPseudo(n, "{1}", "{2}");'
5460             },{
5461                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5463             }, {
5464                 re: /^#([\w-]+)/,
5465                 select: 'n = byId(n, null, "{1}");'
5466             },{
5467                 re: /^@([\w-]+)/,
5468                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5469             }
5470         ],
5471
5472         /**
5473          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5475          */
5476         operators : {
5477             "=" : function(a, v){
5478                 return a == v;
5479             },
5480             "!=" : function(a, v){
5481                 return a != v;
5482             },
5483             "^=" : function(a, v){
5484                 return a && a.substr(0, v.length) == v;
5485             },
5486             "$=" : function(a, v){
5487                 return a && a.substr(a.length-v.length) == v;
5488             },
5489             "*=" : function(a, v){
5490                 return a && a.indexOf(v) !== -1;
5491             },
5492             "%=" : function(a, v){
5493                 return (a % v) == 0;
5494             },
5495             "|=" : function(a, v){
5496                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5497             },
5498             "~=" : function(a, v){
5499                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5500             }
5501         },
5502
5503         /**
5504          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505          * and the argument (if any) supplied in the selector.
5506          */
5507         pseudos : {
5508             "first-child" : function(c){
5509                 var r = [], ri = -1, n;
5510                 for(var i = 0, ci; ci = n = c[i]; i++){
5511                     while((n = n.previousSibling) && n.nodeType != 1);
5512                     if(!n){
5513                         r[++ri] = ci;
5514                     }
5515                 }
5516                 return r;
5517             },
5518
5519             "last-child" : function(c){
5520                 var r = [], ri = -1, n;
5521                 for(var i = 0, ci; ci = n = c[i]; i++){
5522                     while((n = n.nextSibling) && n.nodeType != 1);
5523                     if(!n){
5524                         r[++ri] = ci;
5525                     }
5526                 }
5527                 return r;
5528             },
5529
5530             "nth-child" : function(c, a) {
5531                 var r = [], ri = -1;
5532                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534                 for(var i = 0, n; n = c[i]; i++){
5535                     var pn = n.parentNode;
5536                     if (batch != pn._batch) {
5537                         var j = 0;
5538                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539                             if(cn.nodeType == 1){
5540                                cn.nodeIndex = ++j;
5541                             }
5542                         }
5543                         pn._batch = batch;
5544                     }
5545                     if (f == 1) {
5546                         if (l == 0 || n.nodeIndex == l){
5547                             r[++ri] = n;
5548                         }
5549                     } else if ((n.nodeIndex + l) % f == 0){
5550                         r[++ri] = n;
5551                     }
5552                 }
5553
5554                 return r;
5555             },
5556
5557             "only-child" : function(c){
5558                 var r = [], ri = -1;;
5559                 for(var i = 0, ci; ci = c[i]; i++){
5560                     if(!prev(ci) && !next(ci)){
5561                         r[++ri] = ci;
5562                     }
5563                 }
5564                 return r;
5565             },
5566
5567             "empty" : function(c){
5568                 var r = [], ri = -1;
5569                 for(var i = 0, ci; ci = c[i]; i++){
5570                     var cns = ci.childNodes, j = 0, cn, empty = true;
5571                     while(cn = cns[j]){
5572                         ++j;
5573                         if(cn.nodeType == 1 || cn.nodeType == 3){
5574                             empty = false;
5575                             break;
5576                         }
5577                     }
5578                     if(empty){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "contains" : function(c, v){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "nodeValue" : function(c, v){
5596                 var r = [], ri = -1;
5597                 for(var i = 0, ci; ci = c[i]; i++){
5598                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5599                         r[++ri] = ci;
5600                     }
5601                 }
5602                 return r;
5603             },
5604
5605             "checked" : function(c){
5606                 var r = [], ri = -1;
5607                 for(var i = 0, ci; ci = c[i]; i++){
5608                     if(ci.checked == true){
5609                         r[++ri] = ci;
5610                     }
5611                 }
5612                 return r;
5613             },
5614
5615             "not" : function(c, ss){
5616                 return Roo.DomQuery.filter(c, ss, true);
5617             },
5618
5619             "odd" : function(c){
5620                 return this["nth-child"](c, "odd");
5621             },
5622
5623             "even" : function(c){
5624                 return this["nth-child"](c, "even");
5625             },
5626
5627             "nth" : function(c, a){
5628                 return c[a-1] || [];
5629             },
5630
5631             "first" : function(c){
5632                 return c[0] || [];
5633             },
5634
5635             "last" : function(c){
5636                 return c[c.length-1] || [];
5637             },
5638
5639             "has" : function(c, ss){
5640                 var s = Roo.DomQuery.select;
5641                 var r = [], ri = -1;
5642                 for(var i = 0, ci; ci = c[i]; i++){
5643                     if(s(ss, ci).length > 0){
5644                         r[++ri] = ci;
5645                     }
5646                 }
5647                 return r;
5648             },
5649
5650             "next" : function(c, ss){
5651                 var is = Roo.DomQuery.is;
5652                 var r = [], ri = -1;
5653                 for(var i = 0, ci; ci = c[i]; i++){
5654                     var n = next(ci);
5655                     if(n && is(n, ss)){
5656                         r[++ri] = ci;
5657                     }
5658                 }
5659                 return r;
5660             },
5661
5662             "prev" : function(c, ss){
5663                 var is = Roo.DomQuery.is;
5664                 var r = [], ri = -1;
5665                 for(var i = 0, ci; ci = c[i]; i++){
5666                     var n = prev(ci);
5667                     if(n && is(n, ss)){
5668                         r[++ri] = ci;
5669                     }
5670                 }
5671                 return r;
5672             }
5673         }
5674     };
5675 }();
5676
5677 /**
5678  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679  * @param {String} path The selector/xpath query
5680  * @param {Node} root (optional) The start of the query (defaults to document).
5681  * @return {Array}
5682  * @member Roo
5683  * @method query
5684  */
5685 Roo.query = Roo.DomQuery.select;
5686 /*
5687  * Based on:
5688  * Ext JS Library 1.1.1
5689  * Copyright(c) 2006-2007, Ext JS, LLC.
5690  *
5691  * Originally Released Under LGPL - original licence link has changed is not relivant.
5692  *
5693  * Fork - LGPL
5694  * <script type="text/javascript">
5695  */
5696
5697 /**
5698  * @class Roo.util.Observable
5699  * Base class that provides a common interface for publishing events. Subclasses are expected to
5700  * to have a property "events" with all the events defined.<br>
5701  * For example:
5702  * <pre><code>
5703  Employee = function(name){
5704     this.name = name;
5705     this.addEvents({
5706         "fired" : true,
5707         "quit" : true
5708     });
5709  }
5710  Roo.extend(Employee, Roo.util.Observable);
5711 </code></pre>
5712  * @param {Object} config properties to use (incuding events / listeners)
5713  */
5714
5715 Roo.util.Observable = function(cfg){
5716     
5717     cfg = cfg|| {};
5718     this.addEvents(cfg.events || {});
5719     if (cfg.events) {
5720         delete cfg.events; // make sure
5721     }
5722      
5723     Roo.apply(this, cfg);
5724     
5725     if(this.listeners){
5726         this.on(this.listeners);
5727         delete this.listeners;
5728     }
5729 };
5730 Roo.util.Observable.prototype = {
5731     /** 
5732  * @cfg {Object} listeners  list of events and functions to call for this object, 
5733  * For example :
5734  * <pre><code>
5735     listeners :  { 
5736        'click' : function(e) {
5737            ..... 
5738         } ,
5739         .... 
5740     } 
5741   </code></pre>
5742  */
5743     
5744     
5745     /**
5746      * Fires the specified event with the passed parameters (minus the event name).
5747      * @param {String} eventName
5748      * @param {Object...} args Variable number of parameters are passed to handlers
5749      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5750      */
5751     fireEvent : function(){
5752         var ce = this.events[arguments[0].toLowerCase()];
5753         if(typeof ce == "object"){
5754             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5755         }else{
5756             return true;
5757         }
5758     },
5759
5760     // private
5761     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5762
5763     /**
5764      * Appends an event handler to this component
5765      * @param {String}   eventName The type of event to listen for
5766      * @param {Function} handler The method the event invokes
5767      * @param {Object}   scope (optional) The scope in which to execute the handler
5768      * function. The handler function's "this" context.
5769      * @param {Object}   options (optional) An object containing handler configuration
5770      * properties. This may contain any of the following properties:<ul>
5771      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775      * by the specified number of milliseconds. If the event fires again within that time, the original
5776      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5777      * </ul><br>
5778      * <p>
5779      * <b>Combining Options</b><br>
5780      * Using the options argument, it is possible to combine different types of listeners:<br>
5781      * <br>
5782      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5783                 <pre><code>
5784                 el.on('click', this.onClick, this, {
5785                         single: true,
5786                 delay: 100,
5787                 forumId: 4
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * <b>Attaching multiple handlers in 1 call</b><br>
5792      * The method also allows for a single argument to be passed which is a config object containing properties
5793      * which specify multiple handlers.
5794      * <pre><code>
5795                 el.on({
5796                         'click': {
5797                         fn: this.onClick,
5798                         scope: this,
5799                         delay: 100
5800                 }, 
5801                 'mouseover': {
5802                         fn: this.onMouseOver,
5803                         scope: this
5804                 },
5805                 'mouseout': {
5806                         fn: this.onMouseOut,
5807                         scope: this
5808                 }
5809                 });
5810                 </code></pre>
5811      * <p>
5812      * Or a shorthand syntax which passes the same scope object to all handlers:
5813         <pre><code>
5814                 el.on({
5815                         'click': this.onClick,
5816                 'mouseover': this.onMouseOver,
5817                 'mouseout': this.onMouseOut,
5818                 scope: this
5819                 });
5820                 </code></pre>
5821      */
5822     addListener : function(eventName, fn, scope, o){
5823         if(typeof eventName == "object"){
5824             o = eventName;
5825             for(var e in o){
5826                 if(this.filterOptRe.test(e)){
5827                     continue;
5828                 }
5829                 if(typeof o[e] == "function"){
5830                     // shared options
5831                     this.addListener(e, o[e], o.scope,  o);
5832                 }else{
5833                     // individual options
5834                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5835                 }
5836             }
5837             return;
5838         }
5839         o = (!o || typeof o == "boolean") ? {} : o;
5840         eventName = eventName.toLowerCase();
5841         var ce = this.events[eventName] || true;
5842         if(typeof ce == "boolean"){
5843             ce = new Roo.util.Event(this, eventName);
5844             this.events[eventName] = ce;
5845         }
5846         ce.addListener(fn, scope, o);
5847     },
5848
5849     /**
5850      * Removes a listener
5851      * @param {String}   eventName     The type of event to listen for
5852      * @param {Function} handler        The handler to remove
5853      * @param {Object}   scope  (optional) The scope (this object) for the handler
5854      */
5855     removeListener : function(eventName, fn, scope){
5856         var ce = this.events[eventName.toLowerCase()];
5857         if(typeof ce == "object"){
5858             ce.removeListener(fn, scope);
5859         }
5860     },
5861
5862     /**
5863      * Removes all listeners for this object
5864      */
5865     purgeListeners : function(){
5866         for(var evt in this.events){
5867             if(typeof this.events[evt] == "object"){
5868                  this.events[evt].clearListeners();
5869             }
5870         }
5871     },
5872
5873     relayEvents : function(o, events){
5874         var createHandler = function(ename){
5875             return function(){
5876                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5877             };
5878         };
5879         for(var i = 0, len = events.length; i < len; i++){
5880             var ename = events[i];
5881             if(!this.events[ename]){ this.events[ename] = true; };
5882             o.on(ename, createHandler(ename), this);
5883         }
5884     },
5885
5886     /**
5887      * Used to define events on this Observable
5888      * @param {Object} object The object with the events defined
5889      */
5890     addEvents : function(o){
5891         if(!this.events){
5892             this.events = {};
5893         }
5894         Roo.applyIf(this.events, o);
5895     },
5896
5897     /**
5898      * Checks to see if this object has any listeners for a specified event
5899      * @param {String} eventName The name of the event to check for
5900      * @return {Boolean} True if the event is being listened for, else false
5901      */
5902     hasListener : function(eventName){
5903         var e = this.events[eventName];
5904         return typeof e == "object" && e.listeners.length > 0;
5905     }
5906 };
5907 /**
5908  * Appends an event handler to this element (shorthand for addListener)
5909  * @param {String}   eventName     The type of event to listen for
5910  * @param {Function} handler        The method the event invokes
5911  * @param {Object}   scope (optional) The scope in which to execute the handler
5912  * function. The handler function's "this" context.
5913  * @param {Object}   options  (optional)
5914  * @method
5915  */
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5917 /**
5918  * Removes a listener (shorthand for removeListener)
5919  * @param {String}   eventName     The type of event to listen for
5920  * @param {Function} handler        The handler to remove
5921  * @param {Object}   scope  (optional) The scope (this object) for the handler
5922  * @method
5923  */
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5925
5926 /**
5927  * Starts capture on the specified Observable. All events will be passed
5928  * to the supplied function with the event name + standard signature of the event
5929  * <b>before</b> the event is fired. If the supplied function returns false,
5930  * the event will not fire.
5931  * @param {Observable} o The Observable to capture
5932  * @param {Function} fn The function to call
5933  * @param {Object} scope (optional) The scope (this object) for the fn
5934  * @static
5935  */
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5938 };
5939
5940 /**
5941  * Removes <b>all</b> added captures from the Observable.
5942  * @param {Observable} o The Observable to release
5943  * @static
5944  */
5945 Roo.util.Observable.releaseCapture = function(o){
5946     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5947 };
5948
5949 (function(){
5950
5951     var createBuffered = function(h, o, scope){
5952         var task = new Roo.util.DelayedTask();
5953         return function(){
5954             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5955         };
5956     };
5957
5958     var createSingle = function(h, e, fn, scope){
5959         return function(){
5960             e.removeListener(fn, scope);
5961             return h.apply(scope, arguments);
5962         };
5963     };
5964
5965     var createDelayed = function(h, o, scope){
5966         return function(){
5967             var args = Array.prototype.slice.call(arguments, 0);
5968             setTimeout(function(){
5969                 h.apply(scope, args);
5970             }, o.delay || 10);
5971         };
5972     };
5973
5974     Roo.util.Event = function(obj, name){
5975         this.name = name;
5976         this.obj = obj;
5977         this.listeners = [];
5978     };
5979
5980     Roo.util.Event.prototype = {
5981         addListener : function(fn, scope, options){
5982             var o = options || {};
5983             scope = scope || this.obj;
5984             if(!this.isListening(fn, scope)){
5985                 var l = {fn: fn, scope: scope, options: o};
5986                 var h = fn;
5987                 if(o.delay){
5988                     h = createDelayed(h, o, scope);
5989                 }
5990                 if(o.single){
5991                     h = createSingle(h, this, fn, scope);
5992                 }
5993                 if(o.buffer){
5994                     h = createBuffered(h, o, scope);
5995                 }
5996                 l.fireFn = h;
5997                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998                     this.listeners.push(l);
5999                 }else{
6000                     this.listeners = this.listeners.slice(0);
6001                     this.listeners.push(l);
6002                 }
6003             }
6004         },
6005
6006         findListener : function(fn, scope){
6007             scope = scope || this.obj;
6008             var ls = this.listeners;
6009             for(var i = 0, len = ls.length; i < len; i++){
6010                 var l = ls[i];
6011                 if(l.fn == fn && l.scope == scope){
6012                     return i;
6013                 }
6014             }
6015             return -1;
6016         },
6017
6018         isListening : function(fn, scope){
6019             return this.findListener(fn, scope) != -1;
6020         },
6021
6022         removeListener : function(fn, scope){
6023             var index;
6024             if((index = this.findListener(fn, scope)) != -1){
6025                 if(!this.firing){
6026                     this.listeners.splice(index, 1);
6027                 }else{
6028                     this.listeners = this.listeners.slice(0);
6029                     this.listeners.splice(index, 1);
6030                 }
6031                 return true;
6032             }
6033             return false;
6034         },
6035
6036         clearListeners : function(){
6037             this.listeners = [];
6038         },
6039
6040         fire : function(){
6041             var ls = this.listeners, scope, len = ls.length;
6042             if(len > 0){
6043                 this.firing = true;
6044                 var args = Array.prototype.slice.call(arguments, 0);
6045                 for(var i = 0; i < len; i++){
6046                     var l = ls[i];
6047                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048                         this.firing = false;
6049                         return false;
6050                     }
6051                 }
6052                 this.firing = false;
6053             }
6054             return true;
6055         }
6056     };
6057 })();/*
6058  * RooJS Library 
6059  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6060  *
6061  * Licence LGPL 
6062  *
6063  */
6064  
6065 /**
6066  * @class Roo.Document
6067  * @extends Roo.util.Observable
6068  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6069  * 
6070  * @param {Object} config the methods and properties of the 'base' class for the application.
6071  * 
6072  *  Generic Page handler - implement this to start your app..
6073  * 
6074  * eg.
6075  *  MyProject = new Roo.Document({
6076         events : {
6077             'load' : true // your events..
6078         },
6079         listeners : {
6080             'ready' : function() {
6081                 // fired on Roo.onReady()
6082             }
6083         }
6084  * 
6085  */
6086 Roo.Document = function(cfg) {
6087      
6088     this.addEvents({ 
6089         'ready' : true
6090     });
6091     Roo.util.Observable.call(this,cfg);
6092     
6093     var _this = this;
6094     
6095     Roo.onReady(function() {
6096         _this.fireEvent('ready');
6097     },null,false);
6098     
6099     
6100 }
6101
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6103  * Based on:
6104  * Ext JS Library 1.1.1
6105  * Copyright(c) 2006-2007, Ext JS, LLC.
6106  *
6107  * Originally Released Under LGPL - original licence link has changed is not relivant.
6108  *
6109  * Fork - LGPL
6110  * <script type="text/javascript">
6111  */
6112
6113 /**
6114  * @class Roo.EventManager
6115  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6116  * several useful events directly.
6117  * See {@link Roo.EventObject} for more details on normalized event objects.
6118  * @singleton
6119  */
6120 Roo.EventManager = function(){
6121     var docReadyEvent, docReadyProcId, docReadyState = false;
6122     var resizeEvent, resizeTask, textEvent, textSize;
6123     var E = Roo.lib.Event;
6124     var D = Roo.lib.Dom;
6125
6126     
6127     
6128
6129     var fireDocReady = function(){
6130         if(!docReadyState){
6131             docReadyState = true;
6132             Roo.isReady = true;
6133             if(docReadyProcId){
6134                 clearInterval(docReadyProcId);
6135             }
6136             if(Roo.isGecko || Roo.isOpera) {
6137                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6138             }
6139             if(Roo.isIE){
6140                 var defer = document.getElementById("ie-deferred-loader");
6141                 if(defer){
6142                     defer.onreadystatechange = null;
6143                     defer.parentNode.removeChild(defer);
6144                 }
6145             }
6146             if(docReadyEvent){
6147                 docReadyEvent.fire();
6148                 docReadyEvent.clearListeners();
6149             }
6150         }
6151     };
6152     
6153     var initDocReady = function(){
6154         docReadyEvent = new Roo.util.Event();
6155         if(Roo.isGecko || Roo.isOpera) {
6156             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6157         }else if(Roo.isIE){
6158             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159             var defer = document.getElementById("ie-deferred-loader");
6160             defer.onreadystatechange = function(){
6161                 if(this.readyState == "complete"){
6162                     fireDocReady();
6163                 }
6164             };
6165         }else if(Roo.isSafari){ 
6166             docReadyProcId = setInterval(function(){
6167                 var rs = document.readyState;
6168                 if(rs == "complete") {
6169                     fireDocReady();     
6170                  }
6171             }, 10);
6172         }
6173         // no matter what, make sure it fires on load
6174         E.on(window, "load", fireDocReady);
6175     };
6176
6177     var createBuffered = function(h, o){
6178         var task = new Roo.util.DelayedTask(h);
6179         return function(e){
6180             // create new event object impl so new events don't wipe out properties
6181             e = new Roo.EventObjectImpl(e);
6182             task.delay(o.buffer, h, null, [e]);
6183         };
6184     };
6185
6186     var createSingle = function(h, el, ename, fn){
6187         return function(e){
6188             Roo.EventManager.removeListener(el, ename, fn);
6189             h(e);
6190         };
6191     };
6192
6193     var createDelayed = function(h, o){
6194         return function(e){
6195             // create new event object impl so new events don't wipe out properties
6196             e = new Roo.EventObjectImpl(e);
6197             setTimeout(function(){
6198                 h(e);
6199             }, o.delay || 10);
6200         };
6201     };
6202     var transitionEndVal = false;
6203     
6204     var transitionEnd = function()
6205     {
6206         if (transitionEndVal) {
6207             return transitionEndVal;
6208         }
6209         var el = document.createElement('div');
6210
6211         var transEndEventNames = {
6212             WebkitTransition : 'webkitTransitionEnd',
6213             MozTransition    : 'transitionend',
6214             OTransition      : 'oTransitionEnd otransitionend',
6215             transition       : 'transitionend'
6216         };
6217     
6218         for (var name in transEndEventNames) {
6219             if (el.style[name] !== undefined) {
6220                 transitionEndVal = transEndEventNames[name];
6221                 return  transitionEndVal ;
6222             }
6223         }
6224     }
6225     
6226
6227     var listen = function(element, ename, opt, fn, scope){
6228         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229         fn = fn || o.fn; scope = scope || o.scope;
6230         var el = Roo.getDom(element);
6231         
6232         
6233         if(!el){
6234             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6235         }
6236         
6237         if (ename == 'transitionend') {
6238             ename = transitionEnd();
6239         }
6240         var h = function(e){
6241             e = Roo.EventObject.setEvent(e);
6242             var t;
6243             if(o.delegate){
6244                 t = e.getTarget(o.delegate, el);
6245                 if(!t){
6246                     return;
6247                 }
6248             }else{
6249                 t = e.target;
6250             }
6251             if(o.stopEvent === true){
6252                 e.stopEvent();
6253             }
6254             if(o.preventDefault === true){
6255                e.preventDefault();
6256             }
6257             if(o.stopPropagation === true){
6258                 e.stopPropagation();
6259             }
6260
6261             if(o.normalized === false){
6262                 e = e.browserEvent;
6263             }
6264
6265             fn.call(scope || el, e, t, o);
6266         };
6267         if(o.delay){
6268             h = createDelayed(h, o);
6269         }
6270         if(o.single){
6271             h = createSingle(h, el, ename, fn);
6272         }
6273         if(o.buffer){
6274             h = createBuffered(h, o);
6275         }
6276         fn._handlers = fn._handlers || [];
6277         
6278         
6279         fn._handlers.push([Roo.id(el), ename, h]);
6280         
6281         
6282          
6283         E.on(el, ename, h);
6284         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285             el.addEventListener("DOMMouseScroll", h, false);
6286             E.on(window, 'unload', function(){
6287                 el.removeEventListener("DOMMouseScroll", h, false);
6288             });
6289         }
6290         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6292         }
6293         return h;
6294     };
6295
6296     var stopListening = function(el, ename, fn){
6297         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6298         if(hds){
6299             for(var i = 0, len = hds.length; i < len; i++){
6300                 var h = hds[i];
6301                 if(h[0] == id && h[1] == ename){
6302                     hd = h[2];
6303                     hds.splice(i, 1);
6304                     break;
6305                 }
6306             }
6307         }
6308         E.un(el, ename, hd);
6309         el = Roo.getDom(el);
6310         if(ename == "mousewheel" && el.addEventListener){
6311             el.removeEventListener("DOMMouseScroll", hd, false);
6312         }
6313         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6315         }
6316     };
6317
6318     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6319     
6320     var pub = {
6321         
6322         
6323         /** 
6324          * Fix for doc tools
6325          * @scope Roo.EventManager
6326          */
6327         
6328         
6329         /** 
6330          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331          * object with a Roo.EventObject
6332          * @param {Function} fn        The method the event invokes
6333          * @param {Object}   scope    An object that becomes the scope of the handler
6334          * @param {boolean}  override If true, the obj passed in becomes
6335          *                             the execution scope of the listener
6336          * @return {Function} The wrapped function
6337          * @deprecated
6338          */
6339         wrap : function(fn, scope, override){
6340             return function(e){
6341                 Roo.EventObject.setEvent(e);
6342                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6343             };
6344         },
6345         
6346         /**
6347      * Appends an event handler to an element (shorthand for addListener)
6348      * @param {String/HTMLElement}   element        The html element or id to assign the
6349      * @param {String}   eventName The type of event to listen for
6350      * @param {Function} handler The method the event invokes
6351      * @param {Object}   scope (optional) The scope in which to execute the handler
6352      * function. The handler function's "this" context.
6353      * @param {Object}   options (optional) An object containing handler configuration
6354      * properties. This may contain any of the following properties:<ul>
6355      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358      * <li>preventDefault {Boolean} True to prevent the default action</li>
6359      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364      * by the specified number of milliseconds. If the event fires again within that time, the original
6365      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6366      * </ul><br>
6367      * <p>
6368      * <b>Combining Options</b><br>
6369      * Using the options argument, it is possible to combine different types of listeners:<br>
6370      * <br>
6371      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6372      * Code:<pre><code>
6373 el.on('click', this.onClick, this, {
6374     single: true,
6375     delay: 100,
6376     stopEvent : true,
6377     forumId: 4
6378 });</code></pre>
6379      * <p>
6380      * <b>Attaching multiple handlers in 1 call</b><br>
6381       * The method also allows for a single argument to be passed which is a config object containing properties
6382      * which specify multiple handlers.
6383      * <p>
6384      * Code:<pre><code>
6385 el.on({
6386     'click' : {
6387         fn: this.onClick
6388         scope: this,
6389         delay: 100
6390     },
6391     'mouseover' : {
6392         fn: this.onMouseOver
6393         scope: this
6394     },
6395     'mouseout' : {
6396         fn: this.onMouseOut
6397         scope: this
6398     }
6399 });</code></pre>
6400      * <p>
6401      * Or a shorthand syntax:<br>
6402      * Code:<pre><code>
6403 el.on({
6404     'click' : this.onClick,
6405     'mouseover' : this.onMouseOver,
6406     'mouseout' : this.onMouseOut
6407     scope: this
6408 });</code></pre>
6409      */
6410         addListener : function(element, eventName, fn, scope, options){
6411             if(typeof eventName == "object"){
6412                 var o = eventName;
6413                 for(var e in o){
6414                     if(propRe.test(e)){
6415                         continue;
6416                     }
6417                     if(typeof o[e] == "function"){
6418                         // shared options
6419                         listen(element, e, o, o[e], o.scope);
6420                     }else{
6421                         // individual options
6422                         listen(element, e, o[e]);
6423                     }
6424                 }
6425                 return;
6426             }
6427             return listen(element, eventName, options, fn, scope);
6428         },
6429         
6430         /**
6431          * Removes an event handler
6432          *
6433          * @param {String/HTMLElement}   element        The id or html element to remove the 
6434          *                             event from
6435          * @param {String}   eventName     The type of event
6436          * @param {Function} fn
6437          * @return {Boolean} True if a listener was actually removed
6438          */
6439         removeListener : function(element, eventName, fn){
6440             return stopListening(element, eventName, fn);
6441         },
6442         
6443         /**
6444          * Fires when the document is ready (before onload and before images are loaded). Can be 
6445          * accessed shorthanded Roo.onReady().
6446          * @param {Function} fn        The method the event invokes
6447          * @param {Object}   scope    An  object that becomes the scope of the handler
6448          * @param {boolean}  options
6449          */
6450         onDocumentReady : function(fn, scope, options){
6451             if(docReadyState){ // if it already fired
6452                 docReadyEvent.addListener(fn, scope, options);
6453                 docReadyEvent.fire();
6454                 docReadyEvent.clearListeners();
6455                 return;
6456             }
6457             if(!docReadyEvent){
6458                 initDocReady();
6459             }
6460             docReadyEvent.addListener(fn, scope, options);
6461         },
6462         
6463         /**
6464          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465          * @param {Function} fn        The method the event invokes
6466          * @param {Object}   scope    An object that becomes the scope of the handler
6467          * @param {boolean}  options
6468          */
6469         onWindowResize : function(fn, scope, options){
6470             if(!resizeEvent){
6471                 resizeEvent = new Roo.util.Event();
6472                 resizeTask = new Roo.util.DelayedTask(function(){
6473                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6474                 });
6475                 E.on(window, "resize", function(){
6476                     if(Roo.isIE){
6477                         resizeTask.delay(50);
6478                     }else{
6479                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6480                     }
6481                 });
6482             }
6483             resizeEvent.addListener(fn, scope, options);
6484         },
6485
6486         /**
6487          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488          * @param {Function} fn        The method the event invokes
6489          * @param {Object}   scope    An object that becomes the scope of the handler
6490          * @param {boolean}  options
6491          */
6492         onTextResize : function(fn, scope, options){
6493             if(!textEvent){
6494                 textEvent = new Roo.util.Event();
6495                 var textEl = new Roo.Element(document.createElement('div'));
6496                 textEl.dom.className = 'x-text-resize';
6497                 textEl.dom.innerHTML = 'X';
6498                 textEl.appendTo(document.body);
6499                 textSize = textEl.dom.offsetHeight;
6500                 setInterval(function(){
6501                     if(textEl.dom.offsetHeight != textSize){
6502                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6503                     }
6504                 }, this.textResizeInterval);
6505             }
6506             textEvent.addListener(fn, scope, options);
6507         },
6508
6509         /**
6510          * Removes the passed window resize listener.
6511          * @param {Function} fn        The method the event invokes
6512          * @param {Object}   scope    The scope of handler
6513          */
6514         removeResizeListener : function(fn, scope){
6515             if(resizeEvent){
6516                 resizeEvent.removeListener(fn, scope);
6517             }
6518         },
6519
6520         // private
6521         fireResize : function(){
6522             if(resizeEvent){
6523                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6524             }   
6525         },
6526         /**
6527          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6528          */
6529         ieDeferSrc : false,
6530         /**
6531          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6532          */
6533         textResizeInterval : 50
6534     };
6535     
6536     /**
6537      * Fix for doc tools
6538      * @scopeAlias pub=Roo.EventManager
6539      */
6540     
6541      /**
6542      * Appends an event handler to an element (shorthand for addListener)
6543      * @param {String/HTMLElement}   element        The html element or id to assign the
6544      * @param {String}   eventName The type of event to listen for
6545      * @param {Function} handler The method the event invokes
6546      * @param {Object}   scope (optional) The scope in which to execute the handler
6547      * function. The handler function's "this" context.
6548      * @param {Object}   options (optional) An object containing handler configuration
6549      * properties. This may contain any of the following properties:<ul>
6550      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553      * <li>preventDefault {Boolean} True to prevent the default action</li>
6554      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559      * by the specified number of milliseconds. If the event fires again within that time, the original
6560      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6561      * </ul><br>
6562      * <p>
6563      * <b>Combining Options</b><br>
6564      * Using the options argument, it is possible to combine different types of listeners:<br>
6565      * <br>
6566      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6567      * Code:<pre><code>
6568 el.on('click', this.onClick, this, {
6569     single: true,
6570     delay: 100,
6571     stopEvent : true,
6572     forumId: 4
6573 });</code></pre>
6574      * <p>
6575      * <b>Attaching multiple handlers in 1 call</b><br>
6576       * The method also allows for a single argument to be passed which is a config object containing properties
6577      * which specify multiple handlers.
6578      * <p>
6579      * Code:<pre><code>
6580 el.on({
6581     'click' : {
6582         fn: this.onClick
6583         scope: this,
6584         delay: 100
6585     },
6586     'mouseover' : {
6587         fn: this.onMouseOver
6588         scope: this
6589     },
6590     'mouseout' : {
6591         fn: this.onMouseOut
6592         scope: this
6593     }
6594 });</code></pre>
6595      * <p>
6596      * Or a shorthand syntax:<br>
6597      * Code:<pre><code>
6598 el.on({
6599     'click' : this.onClick,
6600     'mouseover' : this.onMouseOver,
6601     'mouseout' : this.onMouseOut
6602     scope: this
6603 });</code></pre>
6604      */
6605     pub.on = pub.addListener;
6606     pub.un = pub.removeListener;
6607
6608     pub.stoppedMouseDownEvent = new Roo.util.Event();
6609     return pub;
6610 }();
6611 /**
6612   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613   * @param {Function} fn        The method the event invokes
6614   * @param {Object}   scope    An  object that becomes the scope of the handler
6615   * @param {boolean}  override If true, the obj passed in becomes
6616   *                             the execution scope of the listener
6617   * @member Roo
6618   * @method onReady
6619  */
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6621
6622 Roo.onReady(function(){
6623     var bd = Roo.get(document.body);
6624     if(!bd){ return; }
6625
6626     var cls = [
6627             Roo.isIE ? "roo-ie"
6628             : Roo.isGecko ? "roo-gecko"
6629             : Roo.isOpera ? "roo-opera"
6630             : Roo.isSafari ? "roo-safari" : ""];
6631
6632     if(Roo.isMac){
6633         cls.push("roo-mac");
6634     }
6635     if(Roo.isLinux){
6636         cls.push("roo-linux");
6637     }
6638     if(Roo.isIOS){
6639         cls.push("roo-ios");
6640     }
6641     if(Roo.isTouch){
6642         cls.push("roo-touch");
6643     }
6644     if(Roo.isBorderBox){
6645         cls.push('roo-border-box');
6646     }
6647     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648         var p = bd.dom.parentNode;
6649         if(p){
6650             p.className += ' roo-strict';
6651         }
6652     }
6653     bd.addClass(cls.join(' '));
6654 });
6655
6656 /**
6657  * @class Roo.EventObject
6658  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6660  * Example:
6661  * <pre><code>
6662  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6663     e.preventDefault();
6664     var target = e.getTarget();
6665     ...
6666  }
6667  var myDiv = Roo.get("myDiv");
6668  myDiv.on("click", handleClick);
6669  //or
6670  Roo.EventManager.on("myDiv", 'click', handleClick);
6671  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6672  </code></pre>
6673  * @singleton
6674  */
6675 Roo.EventObject = function(){
6676     
6677     var E = Roo.lib.Event;
6678     
6679     // safari keypress events for special keys return bad keycodes
6680     var safariKeys = {
6681         63234 : 37, // left
6682         63235 : 39, // right
6683         63232 : 38, // up
6684         63233 : 40, // down
6685         63276 : 33, // page up
6686         63277 : 34, // page down
6687         63272 : 46, // delete
6688         63273 : 36, // home
6689         63275 : 35  // end
6690     };
6691
6692     // normalize button clicks
6693     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6695
6696     Roo.EventObjectImpl = function(e){
6697         if(e){
6698             this.setEvent(e.browserEvent || e);
6699         }
6700     };
6701     Roo.EventObjectImpl.prototype = {
6702         /**
6703          * Used to fix doc tools.
6704          * @scope Roo.EventObject.prototype
6705          */
6706             
6707
6708         
6709         
6710         /** The normal browser event */
6711         browserEvent : null,
6712         /** The button pressed in a mouse event */
6713         button : -1,
6714         /** True if the shift key was down during the event */
6715         shiftKey : false,
6716         /** True if the control key was down during the event */
6717         ctrlKey : false,
6718         /** True if the alt key was down during the event */
6719         altKey : false,
6720
6721         /** Key constant 
6722         * @type Number */
6723         BACKSPACE : 8,
6724         /** Key constant 
6725         * @type Number */
6726         TAB : 9,
6727         /** Key constant 
6728         * @type Number */
6729         RETURN : 13,
6730         /** Key constant 
6731         * @type Number */
6732         ENTER : 13,
6733         /** Key constant 
6734         * @type Number */
6735         SHIFT : 16,
6736         /** Key constant 
6737         * @type Number */
6738         CONTROL : 17,
6739         /** Key constant 
6740         * @type Number */
6741         ESC : 27,
6742         /** Key constant 
6743         * @type Number */
6744         SPACE : 32,
6745         /** Key constant 
6746         * @type Number */
6747         PAGEUP : 33,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEDOWN : 34,
6751         /** Key constant 
6752         * @type Number */
6753         END : 35,
6754         /** Key constant 
6755         * @type Number */
6756         HOME : 36,
6757         /** Key constant 
6758         * @type Number */
6759         LEFT : 37,
6760         /** Key constant 
6761         * @type Number */
6762         UP : 38,
6763         /** Key constant 
6764         * @type Number */
6765         RIGHT : 39,
6766         /** Key constant 
6767         * @type Number */
6768         DOWN : 40,
6769         /** Key constant 
6770         * @type Number */
6771         DELETE : 46,
6772         /** Key constant 
6773         * @type Number */
6774         F5 : 116,
6775
6776            /** @private */
6777         setEvent : function(e){
6778             if(e == this || (e && e.browserEvent)){ // already wrapped
6779                 return e;
6780             }
6781             this.browserEvent = e;
6782             if(e){
6783                 // normalize buttons
6784                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785                 if(e.type == 'click' && this.button == -1){
6786                     this.button = 0;
6787                 }
6788                 this.type = e.type;
6789                 this.shiftKey = e.shiftKey;
6790                 // mac metaKey behaves like ctrlKey
6791                 this.ctrlKey = e.ctrlKey || e.metaKey;
6792                 this.altKey = e.altKey;
6793                 // in getKey these will be normalized for the mac
6794                 this.keyCode = e.keyCode;
6795                 // keyup warnings on firefox.
6796                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797                 // cache the target for the delayed and or buffered events
6798                 this.target = E.getTarget(e);
6799                 // same for XY
6800                 this.xy = E.getXY(e);
6801             }else{
6802                 this.button = -1;
6803                 this.shiftKey = false;
6804                 this.ctrlKey = false;
6805                 this.altKey = false;
6806                 this.keyCode = 0;
6807                 this.charCode =0;
6808                 this.target = null;
6809                 this.xy = [0, 0];
6810             }
6811             return this;
6812         },
6813
6814         /**
6815          * Stop the event (preventDefault and stopPropagation)
6816          */
6817         stopEvent : function(){
6818             if(this.browserEvent){
6819                 if(this.browserEvent.type == 'mousedown'){
6820                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6821                 }
6822                 E.stopEvent(this.browserEvent);
6823             }
6824         },
6825
6826         /**
6827          * Prevents the browsers default handling of the event.
6828          */
6829         preventDefault : function(){
6830             if(this.browserEvent){
6831                 E.preventDefault(this.browserEvent);
6832             }
6833         },
6834
6835         /** @private */
6836         isNavKeyPress : function(){
6837             var k = this.keyCode;
6838             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6840         },
6841
6842         isSpecialKey : function(){
6843             var k = this.keyCode;
6844             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6845             (k == 16) || (k == 17) ||
6846             (k >= 18 && k <= 20) ||
6847             (k >= 33 && k <= 35) ||
6848             (k >= 36 && k <= 39) ||
6849             (k >= 44 && k <= 45);
6850         },
6851         /**
6852          * Cancels bubbling of the event.
6853          */
6854         stopPropagation : function(){
6855             if(this.browserEvent){
6856                 if(this.type == 'mousedown'){
6857                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6858                 }
6859                 E.stopPropagation(this.browserEvent);
6860             }
6861         },
6862
6863         /**
6864          * Gets the key code for the event.
6865          * @return {Number}
6866          */
6867         getCharCode : function(){
6868             return this.charCode || this.keyCode;
6869         },
6870
6871         /**
6872          * Returns a normalized keyCode for the event.
6873          * @return {Number} The key code
6874          */
6875         getKey : function(){
6876             var k = this.keyCode || this.charCode;
6877             return Roo.isSafari ? (safariKeys[k] || k) : k;
6878         },
6879
6880         /**
6881          * Gets the x coordinate of the event.
6882          * @return {Number}
6883          */
6884         getPageX : function(){
6885             return this.xy[0];
6886         },
6887
6888         /**
6889          * Gets the y coordinate of the event.
6890          * @return {Number}
6891          */
6892         getPageY : function(){
6893             return this.xy[1];
6894         },
6895
6896         /**
6897          * Gets the time of the event.
6898          * @return {Number}
6899          */
6900         getTime : function(){
6901             if(this.browserEvent){
6902                 return E.getTime(this.browserEvent);
6903             }
6904             return null;
6905         },
6906
6907         /**
6908          * Gets the page coordinates of the event.
6909          * @return {Array} The xy values like [x, y]
6910          */
6911         getXY : function(){
6912             return this.xy;
6913         },
6914
6915         /**
6916          * Gets the target for the event.
6917          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919                 search as a number or element (defaults to 10 || document.body)
6920          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921          * @return {HTMLelement}
6922          */
6923         getTarget : function(selector, maxDepth, returnEl){
6924             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6925         },
6926         /**
6927          * Gets the related target.
6928          * @return {HTMLElement}
6929          */
6930         getRelatedTarget : function(){
6931             if(this.browserEvent){
6932                 return E.getRelatedTarget(this.browserEvent);
6933             }
6934             return null;
6935         },
6936
6937         /**
6938          * Normalizes mouse wheel delta across browsers
6939          * @return {Number} The delta
6940          */
6941         getWheelDelta : function(){
6942             var e = this.browserEvent;
6943             var delta = 0;
6944             if(e.wheelDelta){ /* IE/Opera. */
6945                 delta = e.wheelDelta/120;
6946             }else if(e.detail){ /* Mozilla case. */
6947                 delta = -e.detail/3;
6948             }
6949             return delta;
6950         },
6951
6952         /**
6953          * Returns true if the control, meta, shift or alt key was pressed during this event.
6954          * @return {Boolean}
6955          */
6956         hasModifier : function(){
6957             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6958         },
6959
6960         /**
6961          * Returns true if the target of this event equals el or is a child of el
6962          * @param {String/HTMLElement/Element} el
6963          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6964          * @return {Boolean}
6965          */
6966         within : function(el, related){
6967             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968             return t && Roo.fly(el).contains(t);
6969         },
6970
6971         getPoint : function(){
6972             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6973         }
6974     };
6975
6976     return new Roo.EventObjectImpl();
6977 }();
6978             
6979     /*
6980  * Based on:
6981  * Ext JS Library 1.1.1
6982  * Copyright(c) 2006-2007, Ext JS, LLC.
6983  *
6984  * Originally Released Under LGPL - original licence link has changed is not relivant.
6985  *
6986  * Fork - LGPL
6987  * <script type="text/javascript">
6988  */
6989
6990  
6991 // was in Composite Element!??!?!
6992  
6993 (function(){
6994     var D = Roo.lib.Dom;
6995     var E = Roo.lib.Event;
6996     var A = Roo.lib.Anim;
6997
6998     // local style camelizing for speed
6999     var propCache = {};
7000     var camelRe = /(-[a-z])/gi;
7001     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002     var view = document.defaultView;
7003
7004 /**
7005  * @class Roo.Element
7006  * Represents an Element in the DOM.<br><br>
7007  * Usage:<br>
7008 <pre><code>
7009 var el = Roo.get("my-div");
7010
7011 // or with getEl
7012 var el = getEl("my-div");
7013
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7016 </code></pre>
7017  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018  * each call instead of constructing a new one.<br><br>
7019  * <b>Animations</b><br />
7020  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7022 <pre>
7023 Option    Default   Description
7024 --------- --------  ---------------------------------------------
7025 duration  .35       The duration of the animation in seconds
7026 easing    easeOut   The YUI easing method
7027 callback  none      A function to execute when the anim completes
7028 scope     this      The scope (this) of the callback function
7029 </pre>
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7032 <pre><code>
7033 var el = Roo.get("my-div");
7034
7035 // no animation
7036 el.setWidth(100);
7037
7038 // default animation
7039 el.setWidth(100, true);
7040
7041 // animation with some options set
7042 el.setWidth(100, {
7043     duration: 1,
7044     callback: this.foo,
7045     scope: this
7046 });
7047
7048 // using the "anim" property to get the Anim object
7049 var opt = {
7050     duration: 1,
7051     callback: this.foo,
7052     scope: this
7053 };
7054 el.setWidth(100, opt);
7055 ...
7056 if(opt.anim.isAnimated()){
7057     opt.anim.stop();
7058 }
7059 </code></pre>
7060 * <b> Composite (Collections of) Elements</b><br />
7061  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062  * @constructor Create a new Element directly.
7063  * @param {String/HTMLElement} element
7064  * @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).
7065  */
7066     Roo.Element = function(element, forceNew){
7067         var dom = typeof element == "string" ?
7068                 document.getElementById(element) : element;
7069         if(!dom){ // invalid id/element
7070             return null;
7071         }
7072         var id = dom.id;
7073         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074             return Roo.Element.cache[id];
7075         }
7076
7077         /**
7078          * The DOM element
7079          * @type HTMLElement
7080          */
7081         this.dom = dom;
7082
7083         /**
7084          * The DOM element ID
7085          * @type String
7086          */
7087         this.id = id || Roo.id(dom);
7088     };
7089
7090     var El = Roo.Element;
7091
7092     El.prototype = {
7093         /**
7094          * The element's default display mode  (defaults to "")
7095          * @type String
7096          */
7097         originalDisplay : "",
7098
7099         visibilityMode : 1,
7100         /**
7101          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7102          * @type String
7103          */
7104         defaultUnit : "px",
7105         
7106         /**
7107          * Sets the element's visibility mode. When setVisible() is called it
7108          * will use this to determine whether to set the visibility or the display property.
7109          * @param visMode Element.VISIBILITY or Element.DISPLAY
7110          * @return {Roo.Element} this
7111          */
7112         setVisibilityMode : function(visMode){
7113             this.visibilityMode = visMode;
7114             return this;
7115         },
7116         /**
7117          * Convenience method for setVisibilityMode(Element.DISPLAY)
7118          * @param {String} display (optional) What to set display to when visible
7119          * @return {Roo.Element} this
7120          */
7121         enableDisplayMode : function(display){
7122             this.setVisibilityMode(El.DISPLAY);
7123             if(typeof display != "undefined") { this.originalDisplay = display; }
7124             return this;
7125         },
7126
7127         /**
7128          * 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)
7129          * @param {String} selector The simple selector to test
7130          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131                 search as a number or element (defaults to 10 || document.body)
7132          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7134          */
7135         findParent : function(simpleSelector, maxDepth, returnEl){
7136             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137             maxDepth = maxDepth || 50;
7138             if(typeof maxDepth != "number"){
7139                 stopEl = Roo.getDom(maxDepth);
7140                 maxDepth = 10;
7141             }
7142             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143                 if(dq.is(p, simpleSelector)){
7144                     return returnEl ? Roo.get(p) : p;
7145                 }
7146                 depth++;
7147                 p = p.parentNode;
7148             }
7149             return null;
7150         },
7151
7152
7153         /**
7154          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155          * @param {String} selector The simple selector to test
7156          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157                 search as a number or element (defaults to 10 || document.body)
7158          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7160          */
7161         findParentNode : function(simpleSelector, maxDepth, returnEl){
7162             var p = Roo.fly(this.dom.parentNode, '_internal');
7163             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7164         },
7165         
7166         /**
7167          * Looks at  the scrollable parent element
7168          */
7169         findScrollableParent : function(){
7170             
7171             var el = Roo.get(this.el.dom.parentNode);;
7172             
7173             while (el && !el.isScrollable() && el.dom.nodeName.toLowerCase() != 'body'){
7174                 el = Roo.get(el.dom.parentNode);
7175             }
7176             
7177             if(!el.isScrollable()){
7178                 return null;
7179             }
7180             
7181             return el;
7182         },
7183
7184         /**
7185          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7186          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7187          * @param {String} selector The simple selector to test
7188          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7189                 search as a number or element (defaults to 10 || document.body)
7190          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7191          */
7192         up : function(simpleSelector, maxDepth){
7193             return this.findParentNode(simpleSelector, maxDepth, true);
7194         },
7195
7196
7197
7198         /**
7199          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7200          * @param {String} selector The simple selector to test
7201          * @return {Boolean} True if this element matches the selector, else false
7202          */
7203         is : function(simpleSelector){
7204             return Roo.DomQuery.is(this.dom, simpleSelector);
7205         },
7206
7207         /**
7208          * Perform animation on this element.
7209          * @param {Object} args The YUI animation control args
7210          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7211          * @param {Function} onComplete (optional) Function to call when animation completes
7212          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7213          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7214          * @return {Roo.Element} this
7215          */
7216         animate : function(args, duration, onComplete, easing, animType){
7217             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7218             return this;
7219         },
7220
7221         /*
7222          * @private Internal animation call
7223          */
7224         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7225             animType = animType || 'run';
7226             opt = opt || {};
7227             var anim = Roo.lib.Anim[animType](
7228                 this.dom, args,
7229                 (opt.duration || defaultDur) || .35,
7230                 (opt.easing || defaultEase) || 'easeOut',
7231                 function(){
7232                     Roo.callback(cb, this);
7233                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7234                 },
7235                 this
7236             );
7237             opt.anim = anim;
7238             return anim;
7239         },
7240
7241         // private legacy anim prep
7242         preanim : function(a, i){
7243             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7244         },
7245
7246         /**
7247          * Removes worthless text nodes
7248          * @param {Boolean} forceReclean (optional) By default the element
7249          * keeps track if it has been cleaned already so
7250          * you can call this over and over. However, if you update the element and
7251          * need to force a reclean, you can pass true.
7252          */
7253         clean : function(forceReclean){
7254             if(this.isCleaned && forceReclean !== true){
7255                 return this;
7256             }
7257             var ns = /\S/;
7258             var d = this.dom, n = d.firstChild, ni = -1;
7259             while(n){
7260                 var nx = n.nextSibling;
7261                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7262                     d.removeChild(n);
7263                 }else{
7264                     n.nodeIndex = ++ni;
7265                 }
7266                 n = nx;
7267             }
7268             this.isCleaned = true;
7269             return this;
7270         },
7271
7272         // private
7273         calcOffsetsTo : function(el){
7274             el = Roo.get(el);
7275             var d = el.dom;
7276             var restorePos = false;
7277             if(el.getStyle('position') == 'static'){
7278                 el.position('relative');
7279                 restorePos = true;
7280             }
7281             var x = 0, y =0;
7282             var op = this.dom;
7283             while(op && op != d && op.tagName != 'HTML'){
7284                 x+= op.offsetLeft;
7285                 y+= op.offsetTop;
7286                 op = op.offsetParent;
7287             }
7288             if(restorePos){
7289                 el.position('static');
7290             }
7291             return [x, y];
7292         },
7293
7294         /**
7295          * Scrolls this element into view within the passed container.
7296          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7297          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7298          * @return {Roo.Element} this
7299          */
7300         scrollIntoView : function(container, hscroll){
7301             var c = Roo.getDom(container) || document.body;
7302             var el = this.dom;
7303
7304             var o = this.calcOffsetsTo(c),
7305                 l = o[0],
7306                 t = o[1],
7307                 b = t+el.offsetHeight,
7308                 r = l+el.offsetWidth;
7309
7310             var ch = c.clientHeight;
7311             var ct = parseInt(c.scrollTop, 10);
7312             var cl = parseInt(c.scrollLeft, 10);
7313             var cb = ct + ch;
7314             var cr = cl + c.clientWidth;
7315
7316             if(t < ct){
7317                 c.scrollTop = t;
7318             }else if(b > cb){
7319                 c.scrollTop = b-ch;
7320             }
7321
7322             if(hscroll !== false){
7323                 if(l < cl){
7324                     c.scrollLeft = l;
7325                 }else if(r > cr){
7326                     c.scrollLeft = r-c.clientWidth;
7327                 }
7328             }
7329             return this;
7330         },
7331
7332         // private
7333         scrollChildIntoView : function(child, hscroll){
7334             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7335         },
7336
7337         /**
7338          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7339          * the new height may not be available immediately.
7340          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7341          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7342          * @param {Function} onComplete (optional) Function to call when animation completes
7343          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7344          * @return {Roo.Element} this
7345          */
7346         autoHeight : function(animate, duration, onComplete, easing){
7347             var oldHeight = this.getHeight();
7348             this.clip();
7349             this.setHeight(1); // force clipping
7350             setTimeout(function(){
7351                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7352                 if(!animate){
7353                     this.setHeight(height);
7354                     this.unclip();
7355                     if(typeof onComplete == "function"){
7356                         onComplete();
7357                     }
7358                 }else{
7359                     this.setHeight(oldHeight); // restore original height
7360                     this.setHeight(height, animate, duration, function(){
7361                         this.unclip();
7362                         if(typeof onComplete == "function") { onComplete(); }
7363                     }.createDelegate(this), easing);
7364                 }
7365             }.createDelegate(this), 0);
7366             return this;
7367         },
7368
7369         /**
7370          * Returns true if this element is an ancestor of the passed element
7371          * @param {HTMLElement/String} el The element to check
7372          * @return {Boolean} True if this element is an ancestor of el, else false
7373          */
7374         contains : function(el){
7375             if(!el){return false;}
7376             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7377         },
7378
7379         /**
7380          * Checks whether the element is currently visible using both visibility and display properties.
7381          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7382          * @return {Boolean} True if the element is currently visible, else false
7383          */
7384         isVisible : function(deep) {
7385             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7386             if(deep !== true || !vis){
7387                 return vis;
7388             }
7389             var p = this.dom.parentNode;
7390             while(p && p.tagName.toLowerCase() != "body"){
7391                 if(!Roo.fly(p, '_isVisible').isVisible()){
7392                     return false;
7393                 }
7394                 p = p.parentNode;
7395             }
7396             return true;
7397         },
7398
7399         /**
7400          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7401          * @param {String} selector The CSS selector
7402          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7403          * @return {CompositeElement/CompositeElementLite} The composite element
7404          */
7405         select : function(selector, unique){
7406             return El.select(selector, unique, this.dom);
7407         },
7408
7409         /**
7410          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7411          * @param {String} selector The CSS selector
7412          * @return {Array} An array of the matched nodes
7413          */
7414         query : function(selector, unique){
7415             return Roo.DomQuery.select(selector, this.dom);
7416         },
7417
7418         /**
7419          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7420          * @param {String} selector The CSS selector
7421          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7422          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7423          */
7424         child : function(selector, returnDom){
7425             var n = Roo.DomQuery.selectNode(selector, this.dom);
7426             return returnDom ? n : Roo.get(n);
7427         },
7428
7429         /**
7430          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7431          * @param {String} selector The CSS selector
7432          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7433          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7434          */
7435         down : function(selector, returnDom){
7436             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7437             return returnDom ? n : Roo.get(n);
7438         },
7439
7440         /**
7441          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7442          * @param {String} group The group the DD object is member of
7443          * @param {Object} config The DD config object
7444          * @param {Object} overrides An object containing methods to override/implement on the DD object
7445          * @return {Roo.dd.DD} The DD object
7446          */
7447         initDD : function(group, config, overrides){
7448             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7449             return Roo.apply(dd, overrides);
7450         },
7451
7452         /**
7453          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7454          * @param {String} group The group the DDProxy object is member of
7455          * @param {Object} config The DDProxy config object
7456          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7457          * @return {Roo.dd.DDProxy} The DDProxy object
7458          */
7459         initDDProxy : function(group, config, overrides){
7460             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7461             return Roo.apply(dd, overrides);
7462         },
7463
7464         /**
7465          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7466          * @param {String} group The group the DDTarget object is member of
7467          * @param {Object} config The DDTarget config object
7468          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7469          * @return {Roo.dd.DDTarget} The DDTarget object
7470          */
7471         initDDTarget : function(group, config, overrides){
7472             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7473             return Roo.apply(dd, overrides);
7474         },
7475
7476         /**
7477          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7478          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7479          * @param {Boolean} visible Whether the element is visible
7480          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481          * @return {Roo.Element} this
7482          */
7483          setVisible : function(visible, animate){
7484             if(!animate || !A){
7485                 if(this.visibilityMode == El.DISPLAY){
7486                     this.setDisplayed(visible);
7487                 }else{
7488                     this.fixDisplay();
7489                     this.dom.style.visibility = visible ? "visible" : "hidden";
7490                 }
7491             }else{
7492                 // closure for composites
7493                 var dom = this.dom;
7494                 var visMode = this.visibilityMode;
7495                 if(visible){
7496                     this.setOpacity(.01);
7497                     this.setVisible(true);
7498                 }
7499                 this.anim({opacity: { to: (visible?1:0) }},
7500                       this.preanim(arguments, 1),
7501                       null, .35, 'easeIn', function(){
7502                          if(!visible){
7503                              if(visMode == El.DISPLAY){
7504                                  dom.style.display = "none";
7505                              }else{
7506                                  dom.style.visibility = "hidden";
7507                              }
7508                              Roo.get(dom).setOpacity(1);
7509                          }
7510                      });
7511             }
7512             return this;
7513         },
7514
7515         /**
7516          * Returns true if display is not "none"
7517          * @return {Boolean}
7518          */
7519         isDisplayed : function() {
7520             return this.getStyle("display") != "none";
7521         },
7522
7523         /**
7524          * Toggles the element's visibility or display, depending on visibility mode.
7525          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526          * @return {Roo.Element} this
7527          */
7528         toggle : function(animate){
7529             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7530             return this;
7531         },
7532
7533         /**
7534          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7535          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7536          * @return {Roo.Element} this
7537          */
7538         setDisplayed : function(value) {
7539             if(typeof value == "boolean"){
7540                value = value ? this.originalDisplay : "none";
7541             }
7542             this.setStyle("display", value);
7543             return this;
7544         },
7545
7546         /**
7547          * Tries to focus the element. Any exceptions are caught and ignored.
7548          * @return {Roo.Element} this
7549          */
7550         focus : function() {
7551             try{
7552                 this.dom.focus();
7553             }catch(e){}
7554             return this;
7555         },
7556
7557         /**
7558          * Tries to blur the element. Any exceptions are caught and ignored.
7559          * @return {Roo.Element} this
7560          */
7561         blur : function() {
7562             try{
7563                 this.dom.blur();
7564             }catch(e){}
7565             return this;
7566         },
7567
7568         /**
7569          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7570          * @param {String/Array} className The CSS class to add, or an array of classes
7571          * @return {Roo.Element} this
7572          */
7573         addClass : function(className){
7574             if(className instanceof Array){
7575                 for(var i = 0, len = className.length; i < len; i++) {
7576                     this.addClass(className[i]);
7577                 }
7578             }else{
7579                 if(className && !this.hasClass(className)){
7580                     this.dom.className = this.dom.className + " " + className;
7581                 }
7582             }
7583             return this;
7584         },
7585
7586         /**
7587          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7588          * @param {String/Array} className The CSS class to add, or an array of classes
7589          * @return {Roo.Element} this
7590          */
7591         radioClass : function(className){
7592             var siblings = this.dom.parentNode.childNodes;
7593             for(var i = 0; i < siblings.length; i++) {
7594                 var s = siblings[i];
7595                 if(s.nodeType == 1){
7596                     Roo.get(s).removeClass(className);
7597                 }
7598             }
7599             this.addClass(className);
7600             return this;
7601         },
7602
7603         /**
7604          * Removes one or more CSS classes from the element.
7605          * @param {String/Array} className The CSS class to remove, or an array of classes
7606          * @return {Roo.Element} this
7607          */
7608         removeClass : function(className){
7609             if(!className || !this.dom.className){
7610                 return this;
7611             }
7612             if(className instanceof Array){
7613                 for(var i = 0, len = className.length; i < len; i++) {
7614                     this.removeClass(className[i]);
7615                 }
7616             }else{
7617                 if(this.hasClass(className)){
7618                     var re = this.classReCache[className];
7619                     if (!re) {
7620                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7621                        this.classReCache[className] = re;
7622                     }
7623                     this.dom.className =
7624                         this.dom.className.replace(re, " ");
7625                 }
7626             }
7627             return this;
7628         },
7629
7630         // private
7631         classReCache: {},
7632
7633         /**
7634          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7635          * @param {String} className The CSS class to toggle
7636          * @return {Roo.Element} this
7637          */
7638         toggleClass : function(className){
7639             if(this.hasClass(className)){
7640                 this.removeClass(className);
7641             }else{
7642                 this.addClass(className);
7643             }
7644             return this;
7645         },
7646
7647         /**
7648          * Checks if the specified CSS class exists on this element's DOM node.
7649          * @param {String} className The CSS class to check for
7650          * @return {Boolean} True if the class exists, else false
7651          */
7652         hasClass : function(className){
7653             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7654         },
7655
7656         /**
7657          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7658          * @param {String} oldClassName The CSS class to replace
7659          * @param {String} newClassName The replacement CSS class
7660          * @return {Roo.Element} this
7661          */
7662         replaceClass : function(oldClassName, newClassName){
7663             this.removeClass(oldClassName);
7664             this.addClass(newClassName);
7665             return this;
7666         },
7667
7668         /**
7669          * Returns an object with properties matching the styles requested.
7670          * For example, el.getStyles('color', 'font-size', 'width') might return
7671          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7672          * @param {String} style1 A style name
7673          * @param {String} style2 A style name
7674          * @param {String} etc.
7675          * @return {Object} The style object
7676          */
7677         getStyles : function(){
7678             var a = arguments, len = a.length, r = {};
7679             for(var i = 0; i < len; i++){
7680                 r[a[i]] = this.getStyle(a[i]);
7681             }
7682             return r;
7683         },
7684
7685         /**
7686          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7687          * @param {String} property The style property whose value is returned.
7688          * @return {String} The current value of the style property for this element.
7689          */
7690         getStyle : function(){
7691             return view && view.getComputedStyle ?
7692                 function(prop){
7693                     var el = this.dom, v, cs, camel;
7694                     if(prop == 'float'){
7695                         prop = "cssFloat";
7696                     }
7697                     if(el.style && (v = el.style[prop])){
7698                         return v;
7699                     }
7700                     if(cs = view.getComputedStyle(el, "")){
7701                         if(!(camel = propCache[prop])){
7702                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7703                         }
7704                         return cs[camel];
7705                     }
7706                     return null;
7707                 } :
7708                 function(prop){
7709                     var el = this.dom, v, cs, camel;
7710                     if(prop == 'opacity'){
7711                         if(typeof el.style.filter == 'string'){
7712                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7713                             if(m){
7714                                 var fv = parseFloat(m[1]);
7715                                 if(!isNaN(fv)){
7716                                     return fv ? fv / 100 : 0;
7717                                 }
7718                             }
7719                         }
7720                         return 1;
7721                     }else if(prop == 'float'){
7722                         prop = "styleFloat";
7723                     }
7724                     if(!(camel = propCache[prop])){
7725                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7726                     }
7727                     if(v = el.style[camel]){
7728                         return v;
7729                     }
7730                     if(cs = el.currentStyle){
7731                         return cs[camel];
7732                     }
7733                     return null;
7734                 };
7735         }(),
7736
7737         /**
7738          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7739          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7740          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7741          * @return {Roo.Element} this
7742          */
7743         setStyle : function(prop, value){
7744             if(typeof prop == "string"){
7745                 
7746                 if (prop == 'float') {
7747                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7748                     return this;
7749                 }
7750                 
7751                 var camel;
7752                 if(!(camel = propCache[prop])){
7753                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7754                 }
7755                 
7756                 if(camel == 'opacity') {
7757                     this.setOpacity(value);
7758                 }else{
7759                     this.dom.style[camel] = value;
7760                 }
7761             }else{
7762                 for(var style in prop){
7763                     if(typeof prop[style] != "function"){
7764                        this.setStyle(style, prop[style]);
7765                     }
7766                 }
7767             }
7768             return this;
7769         },
7770
7771         /**
7772          * More flexible version of {@link #setStyle} for setting style properties.
7773          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7774          * a function which returns such a specification.
7775          * @return {Roo.Element} this
7776          */
7777         applyStyles : function(style){
7778             Roo.DomHelper.applyStyles(this.dom, style);
7779             return this;
7780         },
7781
7782         /**
7783           * 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).
7784           * @return {Number} The X position of the element
7785           */
7786         getX : function(){
7787             return D.getX(this.dom);
7788         },
7789
7790         /**
7791           * 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).
7792           * @return {Number} The Y position of the element
7793           */
7794         getY : function(){
7795             return D.getY(this.dom);
7796         },
7797
7798         /**
7799           * 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).
7800           * @return {Array} The XY position of the element
7801           */
7802         getXY : function(){
7803             return D.getXY(this.dom);
7804         },
7805
7806         /**
7807          * 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).
7808          * @param {Number} The X position of the element
7809          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810          * @return {Roo.Element} this
7811          */
7812         setX : function(x, animate){
7813             if(!animate || !A){
7814                 D.setX(this.dom, x);
7815             }else{
7816                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7817             }
7818             return this;
7819         },
7820
7821         /**
7822          * 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).
7823          * @param {Number} The Y position of the element
7824          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7825          * @return {Roo.Element} this
7826          */
7827         setY : function(y, animate){
7828             if(!animate || !A){
7829                 D.setY(this.dom, y);
7830             }else{
7831                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7832             }
7833             return this;
7834         },
7835
7836         /**
7837          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7838          * @param {String} left The left CSS property value
7839          * @return {Roo.Element} this
7840          */
7841         setLeft : function(left){
7842             this.setStyle("left", this.addUnits(left));
7843             return this;
7844         },
7845
7846         /**
7847          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7848          * @param {String} top The top CSS property value
7849          * @return {Roo.Element} this
7850          */
7851         setTop : function(top){
7852             this.setStyle("top", this.addUnits(top));
7853             return this;
7854         },
7855
7856         /**
7857          * Sets the element's CSS right style.
7858          * @param {String} right The right CSS property value
7859          * @return {Roo.Element} this
7860          */
7861         setRight : function(right){
7862             this.setStyle("right", this.addUnits(right));
7863             return this;
7864         },
7865
7866         /**
7867          * Sets the element's CSS bottom style.
7868          * @param {String} bottom The bottom CSS property value
7869          * @return {Roo.Element} this
7870          */
7871         setBottom : function(bottom){
7872             this.setStyle("bottom", this.addUnits(bottom));
7873             return this;
7874         },
7875
7876         /**
7877          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7878          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7879          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7880          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7881          * @return {Roo.Element} this
7882          */
7883         setXY : function(pos, animate){
7884             if(!animate || !A){
7885                 D.setXY(this.dom, pos);
7886             }else{
7887                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7888             }
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 {Number} x X value for new position (coordinates are page-based)
7896          * @param {Number} y Y value for new position (coordinates are page-based)
7897          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7898          * @return {Roo.Element} this
7899          */
7900         setLocation : function(x, y, animate){
7901             this.setXY([x, y], this.preanim(arguments, 2));
7902             return this;
7903         },
7904
7905         /**
7906          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7907          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7908          * @param {Number} x X value for new position (coordinates are page-based)
7909          * @param {Number} y Y value for new position (coordinates are page-based)
7910          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7911          * @return {Roo.Element} this
7912          */
7913         moveTo : function(x, y, animate){
7914             this.setXY([x, y], this.preanim(arguments, 2));
7915             return this;
7916         },
7917
7918         /**
7919          * Returns the region of the given element.
7920          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7921          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7922          */
7923         getRegion : function(){
7924             return D.getRegion(this.dom);
7925         },
7926
7927         /**
7928          * Returns the offset height of the element
7929          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7930          * @return {Number} The element's height
7931          */
7932         getHeight : function(contentHeight){
7933             var h = this.dom.offsetHeight || 0;
7934             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7935         },
7936
7937         /**
7938          * Returns the offset width of the element
7939          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7940          * @return {Number} The element's width
7941          */
7942         getWidth : function(contentWidth){
7943             var w = this.dom.offsetWidth || 0;
7944             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7945         },
7946
7947         /**
7948          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7949          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7950          * if a height has not been set using CSS.
7951          * @return {Number}
7952          */
7953         getComputedHeight : function(){
7954             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7955             if(!h){
7956                 h = parseInt(this.getStyle('height'), 10) || 0;
7957                 if(!this.isBorderBox()){
7958                     h += this.getFrameWidth('tb');
7959                 }
7960             }
7961             return h;
7962         },
7963
7964         /**
7965          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7966          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7967          * if a width has not been set using CSS.
7968          * @return {Number}
7969          */
7970         getComputedWidth : function(){
7971             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7972             if(!w){
7973                 w = parseInt(this.getStyle('width'), 10) || 0;
7974                 if(!this.isBorderBox()){
7975                     w += this.getFrameWidth('lr');
7976                 }
7977             }
7978             return w;
7979         },
7980
7981         /**
7982          * Returns the size of the element.
7983          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7984          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7985          */
7986         getSize : function(contentSize){
7987             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7988         },
7989
7990         /**
7991          * Returns the width and height of the viewport.
7992          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7993          */
7994         getViewSize : function(){
7995             var d = this.dom, doc = document, aw = 0, ah = 0;
7996             if(d == doc || d == doc.body){
7997                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7998             }else{
7999                 return {
8000                     width : d.clientWidth,
8001                     height: d.clientHeight
8002                 };
8003             }
8004         },
8005
8006         /**
8007          * Returns the value of the "value" attribute
8008          * @param {Boolean} asNumber true to parse the value as a number
8009          * @return {String/Number}
8010          */
8011         getValue : function(asNumber){
8012             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8013         },
8014
8015         // private
8016         adjustWidth : function(width){
8017             if(typeof width == "number"){
8018                 if(this.autoBoxAdjust && !this.isBorderBox()){
8019                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8020                 }
8021                 if(width < 0){
8022                     width = 0;
8023                 }
8024             }
8025             return width;
8026         },
8027
8028         // private
8029         adjustHeight : function(height){
8030             if(typeof height == "number"){
8031                if(this.autoBoxAdjust && !this.isBorderBox()){
8032                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8033                }
8034                if(height < 0){
8035                    height = 0;
8036                }
8037             }
8038             return height;
8039         },
8040
8041         /**
8042          * Set the width of the element
8043          * @param {Number} width The new width
8044          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045          * @return {Roo.Element} this
8046          */
8047         setWidth : function(width, animate){
8048             width = this.adjustWidth(width);
8049             if(!animate || !A){
8050                 this.dom.style.width = this.addUnits(width);
8051             }else{
8052                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8053             }
8054             return this;
8055         },
8056
8057         /**
8058          * Set the height of the element
8059          * @param {Number} height The new height
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          setHeight : function(height, animate){
8064             height = this.adjustHeight(height);
8065             if(!animate || !A){
8066                 this.dom.style.height = this.addUnits(height);
8067             }else{
8068                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8069             }
8070             return this;
8071         },
8072
8073         /**
8074          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8075          * @param {Number} width The new width
8076          * @param {Number} height The new height
8077          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8078          * @return {Roo.Element} this
8079          */
8080          setSize : function(width, height, animate){
8081             if(typeof width == "object"){ // in case of object from getSize()
8082                 height = width.height; width = width.width;
8083             }
8084             width = this.adjustWidth(width); height = this.adjustHeight(height);
8085             if(!animate || !A){
8086                 this.dom.style.width = this.addUnits(width);
8087                 this.dom.style.height = this.addUnits(height);
8088             }else{
8089                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8090             }
8091             return this;
8092         },
8093
8094         /**
8095          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8096          * @param {Number} x X value for new position (coordinates are page-based)
8097          * @param {Number} y Y value for new position (coordinates are page-based)
8098          * @param {Number} width The new width
8099          * @param {Number} height The new height
8100          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8101          * @return {Roo.Element} this
8102          */
8103         setBounds : function(x, y, width, height, animate){
8104             if(!animate || !A){
8105                 this.setSize(width, height);
8106                 this.setLocation(x, y);
8107             }else{
8108                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8109                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8110                               this.preanim(arguments, 4), 'motion');
8111             }
8112             return this;
8113         },
8114
8115         /**
8116          * 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.
8117          * @param {Roo.lib.Region} region The region to fill
8118          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8119          * @return {Roo.Element} this
8120          */
8121         setRegion : function(region, animate){
8122             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8123             return this;
8124         },
8125
8126         /**
8127          * Appends an event handler
8128          *
8129          * @param {String}   eventName     The type of event to append
8130          * @param {Function} fn        The method the event invokes
8131          * @param {Object} scope       (optional) The scope (this object) of the fn
8132          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8133          */
8134         addListener : function(eventName, fn, scope, options){
8135             if (this.dom) {
8136                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8137             }
8138         },
8139
8140         /**
8141          * Removes an event handler from this element
8142          * @param {String} eventName the type of event to remove
8143          * @param {Function} fn the method the event invokes
8144          * @return {Roo.Element} this
8145          */
8146         removeListener : function(eventName, fn){
8147             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8148             return this;
8149         },
8150
8151         /**
8152          * Removes all previous added listeners from this element
8153          * @return {Roo.Element} this
8154          */
8155         removeAllListeners : function(){
8156             E.purgeElement(this.dom);
8157             return this;
8158         },
8159
8160         relayEvent : function(eventName, observable){
8161             this.on(eventName, function(e){
8162                 observable.fireEvent(eventName, e);
8163             });
8164         },
8165
8166         /**
8167          * Set the opacity of the element
8168          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8169          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8170          * @return {Roo.Element} this
8171          */
8172          setOpacity : function(opacity, animate){
8173             if(!animate || !A){
8174                 var s = this.dom.style;
8175                 if(Roo.isIE){
8176                     s.zoom = 1;
8177                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8178                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8179                 }else{
8180                     s.opacity = opacity;
8181                 }
8182             }else{
8183                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8184             }
8185             return this;
8186         },
8187
8188         /**
8189          * Gets the left X coordinate
8190          * @param {Boolean} local True to get the local css position instead of page coordinate
8191          * @return {Number}
8192          */
8193         getLeft : function(local){
8194             if(!local){
8195                 return this.getX();
8196             }else{
8197                 return parseInt(this.getStyle("left"), 10) || 0;
8198             }
8199         },
8200
8201         /**
8202          * Gets the right X coordinate of the element (element X position + element width)
8203          * @param {Boolean} local True to get the local css position instead of page coordinate
8204          * @return {Number}
8205          */
8206         getRight : function(local){
8207             if(!local){
8208                 return this.getX() + this.getWidth();
8209             }else{
8210                 return (this.getLeft(true) + this.getWidth()) || 0;
8211             }
8212         },
8213
8214         /**
8215          * Gets the top Y coordinate
8216          * @param {Boolean} local True to get the local css position instead of page coordinate
8217          * @return {Number}
8218          */
8219         getTop : function(local) {
8220             if(!local){
8221                 return this.getY();
8222             }else{
8223                 return parseInt(this.getStyle("top"), 10) || 0;
8224             }
8225         },
8226
8227         /**
8228          * Gets the bottom Y coordinate of the element (element Y position + element height)
8229          * @param {Boolean} local True to get the local css position instead of page coordinate
8230          * @return {Number}
8231          */
8232         getBottom : function(local){
8233             if(!local){
8234                 return this.getY() + this.getHeight();
8235             }else{
8236                 return (this.getTop(true) + this.getHeight()) || 0;
8237             }
8238         },
8239
8240         /**
8241         * Initializes positioning on this element. If a desired position is not passed, it will make the
8242         * the element positioned relative IF it is not already positioned.
8243         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8244         * @param {Number} zIndex (optional) The zIndex to apply
8245         * @param {Number} x (optional) Set the page X position
8246         * @param {Number} y (optional) Set the page Y position
8247         */
8248         position : function(pos, zIndex, x, y){
8249             if(!pos){
8250                if(this.getStyle('position') == 'static'){
8251                    this.setStyle('position', 'relative');
8252                }
8253             }else{
8254                 this.setStyle("position", pos);
8255             }
8256             if(zIndex){
8257                 this.setStyle("z-index", zIndex);
8258             }
8259             if(x !== undefined && y !== undefined){
8260                 this.setXY([x, y]);
8261             }else if(x !== undefined){
8262                 this.setX(x);
8263             }else if(y !== undefined){
8264                 this.setY(y);
8265             }
8266         },
8267
8268         /**
8269         * Clear positioning back to the default when the document was loaded
8270         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8271         * @return {Roo.Element} this
8272          */
8273         clearPositioning : function(value){
8274             value = value ||'';
8275             this.setStyle({
8276                 "left": value,
8277                 "right": value,
8278                 "top": value,
8279                 "bottom": value,
8280                 "z-index": "",
8281                 "position" : "static"
8282             });
8283             return this;
8284         },
8285
8286         /**
8287         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8288         * snapshot before performing an update and then restoring the element.
8289         * @return {Object}
8290         */
8291         getPositioning : function(){
8292             var l = this.getStyle("left");
8293             var t = this.getStyle("top");
8294             return {
8295                 "position" : this.getStyle("position"),
8296                 "left" : l,
8297                 "right" : l ? "" : this.getStyle("right"),
8298                 "top" : t,
8299                 "bottom" : t ? "" : this.getStyle("bottom"),
8300                 "z-index" : this.getStyle("z-index")
8301             };
8302         },
8303
8304         /**
8305          * Gets the width of the border(s) for the specified side(s)
8306          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8307          * passing lr would get the border (l)eft width + the border (r)ight width.
8308          * @return {Number} The width of the sides passed added together
8309          */
8310         getBorderWidth : function(side){
8311             return this.addStyles(side, El.borders);
8312         },
8313
8314         /**
8315          * Gets the width of the padding(s) for the specified side(s)
8316          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8317          * passing lr would get the padding (l)eft + the padding (r)ight.
8318          * @return {Number} The padding of the sides passed added together
8319          */
8320         getPadding : function(side){
8321             return this.addStyles(side, El.paddings);
8322         },
8323
8324         /**
8325         * Set positioning with an object returned by getPositioning().
8326         * @param {Object} posCfg
8327         * @return {Roo.Element} this
8328          */
8329         setPositioning : function(pc){
8330             this.applyStyles(pc);
8331             if(pc.right == "auto"){
8332                 this.dom.style.right = "";
8333             }
8334             if(pc.bottom == "auto"){
8335                 this.dom.style.bottom = "";
8336             }
8337             return this;
8338         },
8339
8340         // private
8341         fixDisplay : function(){
8342             if(this.getStyle("display") == "none"){
8343                 this.setStyle("visibility", "hidden");
8344                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8345                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8346                     this.setStyle("display", "block");
8347                 }
8348             }
8349         },
8350
8351         /**
8352          * Quick set left and top adding default units
8353          * @param {String} left The left CSS property value
8354          * @param {String} top The top CSS property value
8355          * @return {Roo.Element} this
8356          */
8357          setLeftTop : function(left, top){
8358             this.dom.style.left = this.addUnits(left);
8359             this.dom.style.top = this.addUnits(top);
8360             return this;
8361         },
8362
8363         /**
8364          * Move this element relative to its current position.
8365          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8366          * @param {Number} distance How far to move the element in pixels
8367          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368          * @return {Roo.Element} this
8369          */
8370          move : function(direction, distance, animate){
8371             var xy = this.getXY();
8372             direction = direction.toLowerCase();
8373             switch(direction){
8374                 case "l":
8375                 case "left":
8376                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8377                     break;
8378                case "r":
8379                case "right":
8380                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8381                     break;
8382                case "t":
8383                case "top":
8384                case "up":
8385                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8386                     break;
8387                case "b":
8388                case "bottom":
8389                case "down":
8390                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8391                     break;
8392             }
8393             return this;
8394         },
8395
8396         /**
8397          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8398          * @return {Roo.Element} this
8399          */
8400         clip : function(){
8401             if(!this.isClipped){
8402                this.isClipped = true;
8403                this.originalClip = {
8404                    "o": this.getStyle("overflow"),
8405                    "x": this.getStyle("overflow-x"),
8406                    "y": this.getStyle("overflow-y")
8407                };
8408                this.setStyle("overflow", "hidden");
8409                this.setStyle("overflow-x", "hidden");
8410                this.setStyle("overflow-y", "hidden");
8411             }
8412             return this;
8413         },
8414
8415         /**
8416          *  Return clipping (overflow) to original clipping before clip() was called
8417          * @return {Roo.Element} this
8418          */
8419         unclip : function(){
8420             if(this.isClipped){
8421                 this.isClipped = false;
8422                 var o = this.originalClip;
8423                 if(o.o){this.setStyle("overflow", o.o);}
8424                 if(o.x){this.setStyle("overflow-x", o.x);}
8425                 if(o.y){this.setStyle("overflow-y", o.y);}
8426             }
8427             return this;
8428         },
8429
8430
8431         /**
8432          * Gets the x,y coordinates specified by the anchor position on the element.
8433          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8434          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8435          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8436          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8437          * @return {Array} [x, y] An array containing the element's x and y coordinates
8438          */
8439         getAnchorXY : function(anchor, local, s){
8440             //Passing a different size is useful for pre-calculating anchors,
8441             //especially for anchored animations that change the el size.
8442
8443             var w, h, vp = false;
8444             if(!s){
8445                 var d = this.dom;
8446                 if(d == document.body || d == document){
8447                     vp = true;
8448                     w = D.getViewWidth(); h = D.getViewHeight();
8449                 }else{
8450                     w = this.getWidth(); h = this.getHeight();
8451                 }
8452             }else{
8453                 w = s.width;  h = s.height;
8454             }
8455             var x = 0, y = 0, r = Math.round;
8456             switch((anchor || "tl").toLowerCase()){
8457                 case "c":
8458                     x = r(w*.5);
8459                     y = r(h*.5);
8460                 break;
8461                 case "t":
8462                     x = r(w*.5);
8463                     y = 0;
8464                 break;
8465                 case "l":
8466                     x = 0;
8467                     y = r(h*.5);
8468                 break;
8469                 case "r":
8470                     x = w;
8471                     y = r(h*.5);
8472                 break;
8473                 case "b":
8474                     x = r(w*.5);
8475                     y = h;
8476                 break;
8477                 case "tl":
8478                     x = 0;
8479                     y = 0;
8480                 break;
8481                 case "bl":
8482                     x = 0;
8483                     y = h;
8484                 break;
8485                 case "br":
8486                     x = w;
8487                     y = h;
8488                 break;
8489                 case "tr":
8490                     x = w;
8491                     y = 0;
8492                 break;
8493             }
8494             if(local === true){
8495                 return [x, y];
8496             }
8497             if(vp){
8498                 var sc = this.getScroll();
8499                 return [x + sc.left, y + sc.top];
8500             }
8501             //Add the element's offset xy
8502             var o = this.getXY();
8503             return [x+o[0], y+o[1]];
8504         },
8505
8506         /**
8507          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8508          * supported position values.
8509          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8510          * @param {String} position The position to align to.
8511          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8512          * @return {Array} [x, y]
8513          */
8514         getAlignToXY : function(el, p, o){
8515             el = Roo.get(el);
8516             var d = this.dom;
8517             if(!el.dom){
8518                 throw "Element.alignTo with an element that doesn't exist";
8519             }
8520             var c = false; //constrain to viewport
8521             var p1 = "", p2 = "";
8522             o = o || [0,0];
8523
8524             if(!p){
8525                 p = "tl-bl";
8526             }else if(p == "?"){
8527                 p = "tl-bl?";
8528             }else if(p.indexOf("-") == -1){
8529                 p = "tl-" + p;
8530             }
8531             p = p.toLowerCase();
8532             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8533             if(!m){
8534                throw "Element.alignTo with an invalid alignment " + p;
8535             }
8536             p1 = m[1]; p2 = m[2]; c = !!m[3];
8537
8538             //Subtract the aligned el's internal xy from the target's offset xy
8539             //plus custom offset to get the aligned el's new offset xy
8540             var a1 = this.getAnchorXY(p1, true);
8541             var a2 = el.getAnchorXY(p2, false);
8542             var x = a2[0] - a1[0] + o[0];
8543             var y = a2[1] - a1[1] + o[1];
8544             if(c){
8545                 //constrain the aligned el to viewport if necessary
8546                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8547                 // 5px of margin for ie
8548                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8549
8550                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8551                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8552                 //otherwise swap the aligned el to the opposite border of the target.
8553                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8554                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8555                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8556                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8557
8558                var doc = document;
8559                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8560                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8561
8562                if((x+w) > dw + scrollX){
8563                     x = swapX ? r.left-w : dw+scrollX-w;
8564                 }
8565                if(x < scrollX){
8566                    x = swapX ? r.right : scrollX;
8567                }
8568                if((y+h) > dh + scrollY){
8569                     y = swapY ? r.top-h : dh+scrollY-h;
8570                 }
8571                if (y < scrollY){
8572                    y = swapY ? r.bottom : scrollY;
8573                }
8574             }
8575             return [x,y];
8576         },
8577
8578         // private
8579         getConstrainToXY : function(){
8580             var os = {top:0, left:0, bottom:0, right: 0};
8581
8582             return function(el, local, offsets, proposedXY){
8583                 el = Roo.get(el);
8584                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8585
8586                 var vw, vh, vx = 0, vy = 0;
8587                 if(el.dom == document.body || el.dom == document){
8588                     vw = Roo.lib.Dom.getViewWidth();
8589                     vh = Roo.lib.Dom.getViewHeight();
8590                 }else{
8591                     vw = el.dom.clientWidth;
8592                     vh = el.dom.clientHeight;
8593                     if(!local){
8594                         var vxy = el.getXY();
8595                         vx = vxy[0];
8596                         vy = vxy[1];
8597                     }
8598                 }
8599
8600                 var s = el.getScroll();
8601
8602                 vx += offsets.left + s.left;
8603                 vy += offsets.top + s.top;
8604
8605                 vw -= offsets.right;
8606                 vh -= offsets.bottom;
8607
8608                 var vr = vx+vw;
8609                 var vb = vy+vh;
8610
8611                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8612                 var x = xy[0], y = xy[1];
8613                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8614
8615                 // only move it if it needs it
8616                 var moved = false;
8617
8618                 // first validate right/bottom
8619                 if((x + w) > vr){
8620                     x = vr - w;
8621                     moved = true;
8622                 }
8623                 if((y + h) > vb){
8624                     y = vb - h;
8625                     moved = true;
8626                 }
8627                 // then make sure top/left isn't negative
8628                 if(x < vx){
8629                     x = vx;
8630                     moved = true;
8631                 }
8632                 if(y < vy){
8633                     y = vy;
8634                     moved = true;
8635                 }
8636                 return moved ? [x, y] : false;
8637             };
8638         }(),
8639
8640         // private
8641         adjustForConstraints : function(xy, parent, offsets){
8642             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8643         },
8644
8645         /**
8646          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8647          * document it aligns it to the viewport.
8648          * The position parameter is optional, and can be specified in any one of the following formats:
8649          * <ul>
8650          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8651          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8652          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8653          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8654          *   <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
8655          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8656          * </ul>
8657          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8658          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8659          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8660          * that specified in order to enforce the viewport constraints.
8661          * Following are all of the supported anchor positions:
8662     <pre>
8663     Value  Description
8664     -----  -----------------------------
8665     tl     The top left corner (default)
8666     t      The center of the top edge
8667     tr     The top right corner
8668     l      The center of the left edge
8669     c      In the center of the element
8670     r      The center of the right edge
8671     bl     The bottom left corner
8672     b      The center of the bottom edge
8673     br     The bottom right corner
8674     </pre>
8675     Example Usage:
8676     <pre><code>
8677     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8678     el.alignTo("other-el");
8679
8680     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8681     el.alignTo("other-el", "tr?");
8682
8683     // align the bottom right corner of el with the center left edge of other-el
8684     el.alignTo("other-el", "br-l?");
8685
8686     // align the center of el with the bottom left corner of other-el and
8687     // adjust the x position by -6 pixels (and the y position by 0)
8688     el.alignTo("other-el", "c-bl", [-6, 0]);
8689     </code></pre>
8690          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8691          * @param {String} position The position to align to.
8692          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8693          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694          * @return {Roo.Element} this
8695          */
8696         alignTo : function(element, position, offsets, animate){
8697             var xy = this.getAlignToXY(element, position, offsets);
8698             this.setXY(xy, this.preanim(arguments, 3));
8699             return this;
8700         },
8701
8702         /**
8703          * Anchors an element to another element and realigns it when the window is resized.
8704          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8705          * @param {String} position The position to align to.
8706          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8707          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8708          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8709          * is a number, it is used as the buffer delay (defaults to 50ms).
8710          * @param {Function} callback The function to call after the animation finishes
8711          * @return {Roo.Element} this
8712          */
8713         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8714             var action = function(){
8715                 this.alignTo(el, alignment, offsets, animate);
8716                 Roo.callback(callback, this);
8717             };
8718             Roo.EventManager.onWindowResize(action, this);
8719             var tm = typeof monitorScroll;
8720             if(tm != 'undefined'){
8721                 Roo.EventManager.on(window, 'scroll', action, this,
8722                     {buffer: tm == 'number' ? monitorScroll : 50});
8723             }
8724             action.call(this); // align immediately
8725             return this;
8726         },
8727         /**
8728          * Clears any opacity settings from this element. Required in some cases for IE.
8729          * @return {Roo.Element} this
8730          */
8731         clearOpacity : function(){
8732             if (window.ActiveXObject) {
8733                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8734                     this.dom.style.filter = "";
8735                 }
8736             } else {
8737                 this.dom.style.opacity = "";
8738                 this.dom.style["-moz-opacity"] = "";
8739                 this.dom.style["-khtml-opacity"] = "";
8740             }
8741             return this;
8742         },
8743
8744         /**
8745          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8746          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8747          * @return {Roo.Element} this
8748          */
8749         hide : function(animate){
8750             this.setVisible(false, this.preanim(arguments, 0));
8751             return this;
8752         },
8753
8754         /**
8755         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8756         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8757          * @return {Roo.Element} this
8758          */
8759         show : function(animate){
8760             this.setVisible(true, this.preanim(arguments, 0));
8761             return this;
8762         },
8763
8764         /**
8765          * @private Test if size has a unit, otherwise appends the default
8766          */
8767         addUnits : function(size){
8768             return Roo.Element.addUnits(size, this.defaultUnit);
8769         },
8770
8771         /**
8772          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8773          * @return {Roo.Element} this
8774          */
8775         beginMeasure : function(){
8776             var el = this.dom;
8777             if(el.offsetWidth || el.offsetHeight){
8778                 return this; // offsets work already
8779             }
8780             var changed = [];
8781             var p = this.dom, b = document.body; // start with this element
8782             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8783                 var pe = Roo.get(p);
8784                 if(pe.getStyle('display') == 'none'){
8785                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8786                     p.style.visibility = "hidden";
8787                     p.style.display = "block";
8788                 }
8789                 p = p.parentNode;
8790             }
8791             this._measureChanged = changed;
8792             return this;
8793
8794         },
8795
8796         /**
8797          * Restores displays to before beginMeasure was called
8798          * @return {Roo.Element} this
8799          */
8800         endMeasure : function(){
8801             var changed = this._measureChanged;
8802             if(changed){
8803                 for(var i = 0, len = changed.length; i < len; i++) {
8804                     var r = changed[i];
8805                     r.el.style.visibility = r.visibility;
8806                     r.el.style.display = "none";
8807                 }
8808                 this._measureChanged = null;
8809             }
8810             return this;
8811         },
8812
8813         /**
8814         * Update the innerHTML of this element, optionally searching for and processing scripts
8815         * @param {String} html The new HTML
8816         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8817         * @param {Function} callback For async script loading you can be noticed when the update completes
8818         * @return {Roo.Element} this
8819          */
8820         update : function(html, loadScripts, callback){
8821             if(typeof html == "undefined"){
8822                 html = "";
8823             }
8824             if(loadScripts !== true){
8825                 this.dom.innerHTML = html;
8826                 if(typeof callback == "function"){
8827                     callback();
8828                 }
8829                 return this;
8830             }
8831             var id = Roo.id();
8832             var dom = this.dom;
8833
8834             html += '<span id="' + id + '"></span>';
8835
8836             E.onAvailable(id, function(){
8837                 var hd = document.getElementsByTagName("head")[0];
8838                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8839                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8840                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8841
8842                 var match;
8843                 while(match = re.exec(html)){
8844                     var attrs = match[1];
8845                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8846                     if(srcMatch && srcMatch[2]){
8847                        var s = document.createElement("script");
8848                        s.src = srcMatch[2];
8849                        var typeMatch = attrs.match(typeRe);
8850                        if(typeMatch && typeMatch[2]){
8851                            s.type = typeMatch[2];
8852                        }
8853                        hd.appendChild(s);
8854                     }else if(match[2] && match[2].length > 0){
8855                         if(window.execScript) {
8856                            window.execScript(match[2]);
8857                         } else {
8858                             /**
8859                              * eval:var:id
8860                              * eval:var:dom
8861                              * eval:var:html
8862                              * 
8863                              */
8864                            window.eval(match[2]);
8865                         }
8866                     }
8867                 }
8868                 var el = document.getElementById(id);
8869                 if(el){el.parentNode.removeChild(el);}
8870                 if(typeof callback == "function"){
8871                     callback();
8872                 }
8873             });
8874             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8875             return this;
8876         },
8877
8878         /**
8879          * Direct access to the UpdateManager update() method (takes the same parameters).
8880          * @param {String/Function} url The url for this request or a function to call to get the url
8881          * @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}
8882          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8883          * @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.
8884          * @return {Roo.Element} this
8885          */
8886         load : function(){
8887             var um = this.getUpdateManager();
8888             um.update.apply(um, arguments);
8889             return this;
8890         },
8891
8892         /**
8893         * Gets this element's UpdateManager
8894         * @return {Roo.UpdateManager} The UpdateManager
8895         */
8896         getUpdateManager : function(){
8897             if(!this.updateManager){
8898                 this.updateManager = new Roo.UpdateManager(this);
8899             }
8900             return this.updateManager;
8901         },
8902
8903         /**
8904          * Disables text selection for this element (normalized across browsers)
8905          * @return {Roo.Element} this
8906          */
8907         unselectable : function(){
8908             this.dom.unselectable = "on";
8909             this.swallowEvent("selectstart", true);
8910             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8911             this.addClass("x-unselectable");
8912             return this;
8913         },
8914
8915         /**
8916         * Calculates the x, y to center this element on the screen
8917         * @return {Array} The x, y values [x, y]
8918         */
8919         getCenterXY : function(){
8920             return this.getAlignToXY(document, 'c-c');
8921         },
8922
8923         /**
8924         * Centers the Element in either the viewport, or another Element.
8925         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8926         */
8927         center : function(centerIn){
8928             this.alignTo(centerIn || document, 'c-c');
8929             return this;
8930         },
8931
8932         /**
8933          * Tests various css rules/browsers to determine if this element uses a border box
8934          * @return {Boolean}
8935          */
8936         isBorderBox : function(){
8937             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8938         },
8939
8940         /**
8941          * Return a box {x, y, width, height} that can be used to set another elements
8942          * size/location to match this element.
8943          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8944          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8945          * @return {Object} box An object in the format {x, y, width, height}
8946          */
8947         getBox : function(contentBox, local){
8948             var xy;
8949             if(!local){
8950                 xy = this.getXY();
8951             }else{
8952                 var left = parseInt(this.getStyle("left"), 10) || 0;
8953                 var top = parseInt(this.getStyle("top"), 10) || 0;
8954                 xy = [left, top];
8955             }
8956             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8957             if(!contentBox){
8958                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8959             }else{
8960                 var l = this.getBorderWidth("l")+this.getPadding("l");
8961                 var r = this.getBorderWidth("r")+this.getPadding("r");
8962                 var t = this.getBorderWidth("t")+this.getPadding("t");
8963                 var b = this.getBorderWidth("b")+this.getPadding("b");
8964                 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)};
8965             }
8966             bx.right = bx.x + bx.width;
8967             bx.bottom = bx.y + bx.height;
8968             return bx;
8969         },
8970
8971         /**
8972          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8973          for more information about the sides.
8974          * @param {String} sides
8975          * @return {Number}
8976          */
8977         getFrameWidth : function(sides, onlyContentBox){
8978             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8979         },
8980
8981         /**
8982          * 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.
8983          * @param {Object} box The box to fill {x, y, width, height}
8984          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8985          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8986          * @return {Roo.Element} this
8987          */
8988         setBox : function(box, adjust, animate){
8989             var w = box.width, h = box.height;
8990             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8991                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8992                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8993             }
8994             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8995             return this;
8996         },
8997
8998         /**
8999          * Forces the browser to repaint this element
9000          * @return {Roo.Element} this
9001          */
9002          repaint : function(){
9003             var dom = this.dom;
9004             this.addClass("x-repaint");
9005             setTimeout(function(){
9006                 Roo.get(dom).removeClass("x-repaint");
9007             }, 1);
9008             return this;
9009         },
9010
9011         /**
9012          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9013          * then it returns the calculated width of the sides (see getPadding)
9014          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9015          * @return {Object/Number}
9016          */
9017         getMargins : function(side){
9018             if(!side){
9019                 return {
9020                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9021                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9022                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9023                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9024                 };
9025             }else{
9026                 return this.addStyles(side, El.margins);
9027              }
9028         },
9029
9030         // private
9031         addStyles : function(sides, styles){
9032             var val = 0, v, w;
9033             for(var i = 0, len = sides.length; i < len; i++){
9034                 v = this.getStyle(styles[sides.charAt(i)]);
9035                 if(v){
9036                      w = parseInt(v, 10);
9037                      if(w){ val += w; }
9038                 }
9039             }
9040             return val;
9041         },
9042
9043         /**
9044          * Creates a proxy element of this element
9045          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9046          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9047          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9048          * @return {Roo.Element} The new proxy element
9049          */
9050         createProxy : function(config, renderTo, matchBox){
9051             if(renderTo){
9052                 renderTo = Roo.getDom(renderTo);
9053             }else{
9054                 renderTo = document.body;
9055             }
9056             config = typeof config == "object" ?
9057                 config : {tag : "div", cls: config};
9058             var proxy = Roo.DomHelper.append(renderTo, config, true);
9059             if(matchBox){
9060                proxy.setBox(this.getBox());
9061             }
9062             return proxy;
9063         },
9064
9065         /**
9066          * Puts a mask over this element to disable user interaction. Requires core.css.
9067          * This method can only be applied to elements which accept child nodes.
9068          * @param {String} msg (optional) A message to display in the mask
9069          * @param {String} msgCls (optional) A css class to apply to the msg element
9070          * @return {Element} The mask  element
9071          */
9072         mask : function(msg, msgCls)
9073         {
9074             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9075                 this.setStyle("position", "relative");
9076             }
9077             if(!this._mask){
9078                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9079             }
9080             this.addClass("x-masked");
9081             this._mask.setDisplayed(true);
9082             
9083             // we wander
9084             var z = 0;
9085             var dom = this.dom;
9086             while (dom && dom.style) {
9087                 if (!isNaN(parseInt(dom.style.zIndex))) {
9088                     z = Math.max(z, parseInt(dom.style.zIndex));
9089                 }
9090                 dom = dom.parentNode;
9091             }
9092             // if we are masking the body - then it hides everything..
9093             if (this.dom == document.body) {
9094                 z = 1000000;
9095                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9096                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9097             }
9098            
9099             if(typeof msg == 'string'){
9100                 if(!this._maskMsg){
9101                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9102                 }
9103                 var mm = this._maskMsg;
9104                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9105                 if (mm.dom.firstChild) { // weird IE issue?
9106                     mm.dom.firstChild.innerHTML = msg;
9107                 }
9108                 mm.setDisplayed(true);
9109                 mm.center(this);
9110                 mm.setStyle('z-index', z + 102);
9111             }
9112             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9113                 this._mask.setHeight(this.getHeight());
9114             }
9115             this._mask.setStyle('z-index', z + 100);
9116             
9117             return this._mask;
9118         },
9119
9120         /**
9121          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9122          * it is cached for reuse.
9123          */
9124         unmask : function(removeEl){
9125             if(this._mask){
9126                 if(removeEl === true){
9127                     this._mask.remove();
9128                     delete this._mask;
9129                     if(this._maskMsg){
9130                         this._maskMsg.remove();
9131                         delete this._maskMsg;
9132                     }
9133                 }else{
9134                     this._mask.setDisplayed(false);
9135                     if(this._maskMsg){
9136                         this._maskMsg.setDisplayed(false);
9137                     }
9138                 }
9139             }
9140             this.removeClass("x-masked");
9141         },
9142
9143         /**
9144          * Returns true if this element is masked
9145          * @return {Boolean}
9146          */
9147         isMasked : function(){
9148             return this._mask && this._mask.isVisible();
9149         },
9150
9151         /**
9152          * Creates an iframe shim for this element to keep selects and other windowed objects from
9153          * showing through.
9154          * @return {Roo.Element} The new shim element
9155          */
9156         createShim : function(){
9157             var el = document.createElement('iframe');
9158             el.frameBorder = 'no';
9159             el.className = 'roo-shim';
9160             if(Roo.isIE && Roo.isSecure){
9161                 el.src = Roo.SSL_SECURE_URL;
9162             }
9163             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9164             shim.autoBoxAdjust = false;
9165             return shim;
9166         },
9167
9168         /**
9169          * Removes this element from the DOM and deletes it from the cache
9170          */
9171         remove : function(){
9172             if(this.dom.parentNode){
9173                 this.dom.parentNode.removeChild(this.dom);
9174             }
9175             delete El.cache[this.dom.id];
9176         },
9177
9178         /**
9179          * Sets up event handlers to add and remove a css class when the mouse is over this element
9180          * @param {String} className
9181          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9182          * mouseout events for children elements
9183          * @return {Roo.Element} this
9184          */
9185         addClassOnOver : function(className, preventFlicker){
9186             this.on("mouseover", function(){
9187                 Roo.fly(this, '_internal').addClass(className);
9188             }, this.dom);
9189             var removeFn = function(e){
9190                 if(preventFlicker !== true || !e.within(this, true)){
9191                     Roo.fly(this, '_internal').removeClass(className);
9192                 }
9193             };
9194             this.on("mouseout", removeFn, this.dom);
9195             return this;
9196         },
9197
9198         /**
9199          * Sets up event handlers to add and remove a css class when this element has the focus
9200          * @param {String} className
9201          * @return {Roo.Element} this
9202          */
9203         addClassOnFocus : function(className){
9204             this.on("focus", function(){
9205                 Roo.fly(this, '_internal').addClass(className);
9206             }, this.dom);
9207             this.on("blur", function(){
9208                 Roo.fly(this, '_internal').removeClass(className);
9209             }, this.dom);
9210             return this;
9211         },
9212         /**
9213          * 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)
9214          * @param {String} className
9215          * @return {Roo.Element} this
9216          */
9217         addClassOnClick : function(className){
9218             var dom = this.dom;
9219             this.on("mousedown", function(){
9220                 Roo.fly(dom, '_internal').addClass(className);
9221                 var d = Roo.get(document);
9222                 var fn = function(){
9223                     Roo.fly(dom, '_internal').removeClass(className);
9224                     d.removeListener("mouseup", fn);
9225                 };
9226                 d.on("mouseup", fn);
9227             });
9228             return this;
9229         },
9230
9231         /**
9232          * Stops the specified event from bubbling and optionally prevents the default action
9233          * @param {String} eventName
9234          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9235          * @return {Roo.Element} this
9236          */
9237         swallowEvent : function(eventName, preventDefault){
9238             var fn = function(e){
9239                 e.stopPropagation();
9240                 if(preventDefault){
9241                     e.preventDefault();
9242                 }
9243             };
9244             if(eventName instanceof Array){
9245                 for(var i = 0, len = eventName.length; i < len; i++){
9246                      this.on(eventName[i], fn);
9247                 }
9248                 return this;
9249             }
9250             this.on(eventName, fn);
9251             return this;
9252         },
9253
9254         /**
9255          * @private
9256          */
9257       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9258
9259         /**
9260          * Sizes this element to its parent element's dimensions performing
9261          * neccessary box adjustments.
9262          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9263          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9264          * @return {Roo.Element} this
9265          */
9266         fitToParent : function(monitorResize, targetParent) {
9267           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9268           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9269           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9270             return;
9271           }
9272           var p = Roo.get(targetParent || this.dom.parentNode);
9273           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9274           if (monitorResize === true) {
9275             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9276             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9277           }
9278           return this;
9279         },
9280
9281         /**
9282          * Gets the next sibling, skipping text nodes
9283          * @return {HTMLElement} The next sibling or null
9284          */
9285         getNextSibling : function(){
9286             var n = this.dom.nextSibling;
9287             while(n && n.nodeType != 1){
9288                 n = n.nextSibling;
9289             }
9290             return n;
9291         },
9292
9293         /**
9294          * Gets the previous sibling, skipping text nodes
9295          * @return {HTMLElement} The previous sibling or null
9296          */
9297         getPrevSibling : function(){
9298             var n = this.dom.previousSibling;
9299             while(n && n.nodeType != 1){
9300                 n = n.previousSibling;
9301             }
9302             return n;
9303         },
9304
9305
9306         /**
9307          * Appends the passed element(s) to this element
9308          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9309          * @return {Roo.Element} this
9310          */
9311         appendChild: function(el){
9312             el = Roo.get(el);
9313             el.appendTo(this);
9314             return this;
9315         },
9316
9317         /**
9318          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9319          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9320          * automatically generated with the specified attributes.
9321          * @param {HTMLElement} insertBefore (optional) a child element of this element
9322          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9323          * @return {Roo.Element} The new child element
9324          */
9325         createChild: function(config, insertBefore, returnDom){
9326             config = config || {tag:'div'};
9327             if(insertBefore){
9328                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9329             }
9330             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9331         },
9332
9333         /**
9334          * Appends this element to the passed element
9335          * @param {String/HTMLElement/Element} el The new parent element
9336          * @return {Roo.Element} this
9337          */
9338         appendTo: function(el){
9339             el = Roo.getDom(el);
9340             el.appendChild(this.dom);
9341             return this;
9342         },
9343
9344         /**
9345          * Inserts this element before the passed element in the DOM
9346          * @param {String/HTMLElement/Element} el The element to insert before
9347          * @return {Roo.Element} this
9348          */
9349         insertBefore: function(el){
9350             el = Roo.getDom(el);
9351             el.parentNode.insertBefore(this.dom, el);
9352             return this;
9353         },
9354
9355         /**
9356          * Inserts this element after the passed element in the DOM
9357          * @param {String/HTMLElement/Element} el The element to insert after
9358          * @return {Roo.Element} this
9359          */
9360         insertAfter: function(el){
9361             el = Roo.getDom(el);
9362             el.parentNode.insertBefore(this.dom, el.nextSibling);
9363             return this;
9364         },
9365
9366         /**
9367          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9368          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9369          * @return {Roo.Element} The new child
9370          */
9371         insertFirst: function(el, returnDom){
9372             el = el || {};
9373             if(typeof el == 'object' && !el.nodeType){ // dh config
9374                 return this.createChild(el, this.dom.firstChild, returnDom);
9375             }else{
9376                 el = Roo.getDom(el);
9377                 this.dom.insertBefore(el, this.dom.firstChild);
9378                 return !returnDom ? Roo.get(el) : el;
9379             }
9380         },
9381
9382         /**
9383          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9384          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385          * @param {String} where (optional) 'before' or 'after' defaults to before
9386          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9387          * @return {Roo.Element} the inserted Element
9388          */
9389         insertSibling: function(el, where, returnDom){
9390             where = where ? where.toLowerCase() : 'before';
9391             el = el || {};
9392             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9393
9394             if(typeof el == 'object' && !el.nodeType){ // dh config
9395                 if(where == 'after' && !this.dom.nextSibling){
9396                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9397                 }else{
9398                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9399                 }
9400
9401             }else{
9402                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9403                             where == 'before' ? this.dom : this.dom.nextSibling);
9404                 if(!returnDom){
9405                     rt = Roo.get(rt);
9406                 }
9407             }
9408             return rt;
9409         },
9410
9411         /**
9412          * Creates and wraps this element with another element
9413          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9414          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9415          * @return {HTMLElement/Element} The newly created wrapper element
9416          */
9417         wrap: function(config, returnDom){
9418             if(!config){
9419                 config = {tag: "div"};
9420             }
9421             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9422             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9423             return newEl;
9424         },
9425
9426         /**
9427          * Replaces the passed element with this element
9428          * @param {String/HTMLElement/Element} el The element to replace
9429          * @return {Roo.Element} this
9430          */
9431         replace: function(el){
9432             el = Roo.get(el);
9433             this.insertBefore(el);
9434             el.remove();
9435             return this;
9436         },
9437
9438         /**
9439          * Inserts an html fragment into this element
9440          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9441          * @param {String} html The HTML fragment
9442          * @param {Boolean} returnEl True to return an Roo.Element
9443          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9444          */
9445         insertHtml : function(where, html, returnEl){
9446             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9447             return returnEl ? Roo.get(el) : el;
9448         },
9449
9450         /**
9451          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9452          * @param {Object} o The object with the attributes
9453          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9454          * @return {Roo.Element} this
9455          */
9456         set : function(o, useSet){
9457             var el = this.dom;
9458             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9459             for(var attr in o){
9460                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9461                 if(attr=="cls"){
9462                     el.className = o["cls"];
9463                 }else{
9464                     if(useSet) {
9465                         el.setAttribute(attr, o[attr]);
9466                     } else {
9467                         el[attr] = o[attr];
9468                     }
9469                 }
9470             }
9471             if(o.style){
9472                 Roo.DomHelper.applyStyles(el, o.style);
9473             }
9474             return this;
9475         },
9476
9477         /**
9478          * Convenience method for constructing a KeyMap
9479          * @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:
9480          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9481          * @param {Function} fn The function to call
9482          * @param {Object} scope (optional) The scope of the function
9483          * @return {Roo.KeyMap} The KeyMap created
9484          */
9485         addKeyListener : function(key, fn, scope){
9486             var config;
9487             if(typeof key != "object" || key instanceof Array){
9488                 config = {
9489                     key: key,
9490                     fn: fn,
9491                     scope: scope
9492                 };
9493             }else{
9494                 config = {
9495                     key : key.key,
9496                     shift : key.shift,
9497                     ctrl : key.ctrl,
9498                     alt : key.alt,
9499                     fn: fn,
9500                     scope: scope
9501                 };
9502             }
9503             return new Roo.KeyMap(this, config);
9504         },
9505
9506         /**
9507          * Creates a KeyMap for this element
9508          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9509          * @return {Roo.KeyMap} The KeyMap created
9510          */
9511         addKeyMap : function(config){
9512             return new Roo.KeyMap(this, config);
9513         },
9514
9515         /**
9516          * Returns true if this element is scrollable.
9517          * @return {Boolean}
9518          */
9519          isScrollable : function(){
9520             var dom = this.dom;
9521             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9522         },
9523
9524         /**
9525          * 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().
9526          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9527          * @param {Number} value The new scroll value
9528          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9529          * @return {Element} this
9530          */
9531
9532         scrollTo : function(side, value, animate){
9533             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9534             if(!animate || !A){
9535                 this.dom[prop] = value;
9536             }else{
9537                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9538                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9539             }
9540             return this;
9541         },
9542
9543         /**
9544          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9545          * within this element's scrollable range.
9546          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9547          * @param {Number} distance How far to scroll the element in pixels
9548          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9549          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9550          * was scrolled as far as it could go.
9551          */
9552          scroll : function(direction, distance, animate){
9553              if(!this.isScrollable()){
9554                  return;
9555              }
9556              var el = this.dom;
9557              var l = el.scrollLeft, t = el.scrollTop;
9558              var w = el.scrollWidth, h = el.scrollHeight;
9559              var cw = el.clientWidth, ch = el.clientHeight;
9560              direction = direction.toLowerCase();
9561              var scrolled = false;
9562              var a = this.preanim(arguments, 2);
9563              switch(direction){
9564                  case "l":
9565                  case "left":
9566                      if(w - l > cw){
9567                          var v = Math.min(l + distance, w-cw);
9568                          this.scrollTo("left", v, a);
9569                          scrolled = true;
9570                      }
9571                      break;
9572                 case "r":
9573                 case "right":
9574                      if(l > 0){
9575                          var v = Math.max(l - distance, 0);
9576                          this.scrollTo("left", v, a);
9577                          scrolled = true;
9578                      }
9579                      break;
9580                 case "t":
9581                 case "top":
9582                 case "up":
9583                      if(t > 0){
9584                          var v = Math.max(t - distance, 0);
9585                          this.scrollTo("top", v, a);
9586                          scrolled = true;
9587                      }
9588                      break;
9589                 case "b":
9590                 case "bottom":
9591                 case "down":
9592                      if(h - t > ch){
9593                          var v = Math.min(t + distance, h-ch);
9594                          this.scrollTo("top", v, a);
9595                          scrolled = true;
9596                      }
9597                      break;
9598              }
9599              return scrolled;
9600         },
9601
9602         /**
9603          * Translates the passed page coordinates into left/top css values for this element
9604          * @param {Number/Array} x The page x or an array containing [x, y]
9605          * @param {Number} y The page y
9606          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9607          */
9608         translatePoints : function(x, y){
9609             if(typeof x == 'object' || x instanceof Array){
9610                 y = x[1]; x = x[0];
9611             }
9612             var p = this.getStyle('position');
9613             var o = this.getXY();
9614
9615             var l = parseInt(this.getStyle('left'), 10);
9616             var t = parseInt(this.getStyle('top'), 10);
9617
9618             if(isNaN(l)){
9619                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9620             }
9621             if(isNaN(t)){
9622                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9623             }
9624
9625             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9626         },
9627
9628         /**
9629          * Returns the current scroll position of the element.
9630          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9631          */
9632         getScroll : function(){
9633             var d = this.dom, doc = document;
9634             if(d == doc || d == doc.body){
9635                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9636                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9637                 return {left: l, top: t};
9638             }else{
9639                 return {left: d.scrollLeft, top: d.scrollTop};
9640             }
9641         },
9642
9643         /**
9644          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9645          * are convert to standard 6 digit hex color.
9646          * @param {String} attr The css attribute
9647          * @param {String} defaultValue The default value to use when a valid color isn't found
9648          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9649          * YUI color anims.
9650          */
9651         getColor : function(attr, defaultValue, prefix){
9652             var v = this.getStyle(attr);
9653             if(!v || v == "transparent" || v == "inherit") {
9654                 return defaultValue;
9655             }
9656             var color = typeof prefix == "undefined" ? "#" : prefix;
9657             if(v.substr(0, 4) == "rgb("){
9658                 var rvs = v.slice(4, v.length -1).split(",");
9659                 for(var i = 0; i < 3; i++){
9660                     var h = parseInt(rvs[i]).toString(16);
9661                     if(h < 16){
9662                         h = "0" + h;
9663                     }
9664                     color += h;
9665                 }
9666             } else {
9667                 if(v.substr(0, 1) == "#"){
9668                     if(v.length == 4) {
9669                         for(var i = 1; i < 4; i++){
9670                             var c = v.charAt(i);
9671                             color +=  c + c;
9672                         }
9673                     }else if(v.length == 7){
9674                         color += v.substr(1);
9675                     }
9676                 }
9677             }
9678             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9679         },
9680
9681         /**
9682          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9683          * gradient background, rounded corners and a 4-way shadow.
9684          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9685          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9686          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9687          * @return {Roo.Element} this
9688          */
9689         boxWrap : function(cls){
9690             cls = cls || 'x-box';
9691             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9692             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9693             return el;
9694         },
9695
9696         /**
9697          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9698          * @param {String} namespace The namespace in which to look for the attribute
9699          * @param {String} name The attribute name
9700          * @return {String} The attribute value
9701          */
9702         getAttributeNS : Roo.isIE ? function(ns, name){
9703             var d = this.dom;
9704             var type = typeof d[ns+":"+name];
9705             if(type != 'undefined' && type != 'unknown'){
9706                 return d[ns+":"+name];
9707             }
9708             return d[name];
9709         } : function(ns, name){
9710             var d = this.dom;
9711             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9712         },
9713         
9714         
9715         /**
9716          * Sets or Returns the value the dom attribute value
9717          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9718          * @param {String} value (optional) The value to set the attribute to
9719          * @return {String} The attribute value
9720          */
9721         attr : function(name){
9722             if (arguments.length > 1) {
9723                 this.dom.setAttribute(name, arguments[1]);
9724                 return arguments[1];
9725             }
9726             if (typeof(name) == 'object') {
9727                 for(var i in name) {
9728                     this.attr(i, name[i]);
9729                 }
9730                 return name;
9731             }
9732             
9733             
9734             if (!this.dom.hasAttribute(name)) {
9735                 return undefined;
9736             }
9737             return this.dom.getAttribute(name);
9738         }
9739         
9740         
9741         
9742     };
9743
9744     var ep = El.prototype;
9745
9746     /**
9747      * Appends an event handler (Shorthand for addListener)
9748      * @param {String}   eventName     The type of event to append
9749      * @param {Function} fn        The method the event invokes
9750      * @param {Object} scope       (optional) The scope (this object) of the fn
9751      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9752      * @method
9753      */
9754     ep.on = ep.addListener;
9755         // backwards compat
9756     ep.mon = ep.addListener;
9757
9758     /**
9759      * Removes an event handler from this element (shorthand for removeListener)
9760      * @param {String} eventName the type of event to remove
9761      * @param {Function} fn the method the event invokes
9762      * @return {Roo.Element} this
9763      * @method
9764      */
9765     ep.un = ep.removeListener;
9766
9767     /**
9768      * true to automatically adjust width and height settings for box-model issues (default to true)
9769      */
9770     ep.autoBoxAdjust = true;
9771
9772     // private
9773     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9774
9775     // private
9776     El.addUnits = function(v, defaultUnit){
9777         if(v === "" || v == "auto"){
9778             return v;
9779         }
9780         if(v === undefined){
9781             return '';
9782         }
9783         if(typeof v == "number" || !El.unitPattern.test(v)){
9784             return v + (defaultUnit || 'px');
9785         }
9786         return v;
9787     };
9788
9789     // special markup used throughout Roo when box wrapping elements
9790     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>';
9791     /**
9792      * Visibility mode constant - Use visibility to hide element
9793      * @static
9794      * @type Number
9795      */
9796     El.VISIBILITY = 1;
9797     /**
9798      * Visibility mode constant - Use display to hide element
9799      * @static
9800      * @type Number
9801      */
9802     El.DISPLAY = 2;
9803
9804     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9805     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9806     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9807
9808
9809
9810     /**
9811      * @private
9812      */
9813     El.cache = {};
9814
9815     var docEl;
9816
9817     /**
9818      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9819      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9820      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9821      * @return {Element} The Element object
9822      * @static
9823      */
9824     El.get = function(el){
9825         var ex, elm, id;
9826         if(!el){ return null; }
9827         if(typeof el == "string"){ // element id
9828             if(!(elm = document.getElementById(el))){
9829                 return null;
9830             }
9831             if(ex = El.cache[el]){
9832                 ex.dom = elm;
9833             }else{
9834                 ex = El.cache[el] = new El(elm);
9835             }
9836             return ex;
9837         }else if(el.tagName){ // dom element
9838             if(!(id = el.id)){
9839                 id = Roo.id(el);
9840             }
9841             if(ex = El.cache[id]){
9842                 ex.dom = el;
9843             }else{
9844                 ex = El.cache[id] = new El(el);
9845             }
9846             return ex;
9847         }else if(el instanceof El){
9848             if(el != docEl){
9849                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9850                                                               // catch case where it hasn't been appended
9851                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9852             }
9853             return el;
9854         }else if(el.isComposite){
9855             return el;
9856         }else if(el instanceof Array){
9857             return El.select(el);
9858         }else if(el == document){
9859             // create a bogus element object representing the document object
9860             if(!docEl){
9861                 var f = function(){};
9862                 f.prototype = El.prototype;
9863                 docEl = new f();
9864                 docEl.dom = document;
9865             }
9866             return docEl;
9867         }
9868         return null;
9869     };
9870
9871     // private
9872     El.uncache = function(el){
9873         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9874             if(a[i]){
9875                 delete El.cache[a[i].id || a[i]];
9876             }
9877         }
9878     };
9879
9880     // private
9881     // Garbage collection - uncache elements/purge listeners on orphaned elements
9882     // so we don't hold a reference and cause the browser to retain them
9883     El.garbageCollect = function(){
9884         if(!Roo.enableGarbageCollector){
9885             clearInterval(El.collectorThread);
9886             return;
9887         }
9888         for(var eid in El.cache){
9889             var el = El.cache[eid], d = el.dom;
9890             // -------------------------------------------------------
9891             // Determining what is garbage:
9892             // -------------------------------------------------------
9893             // !d
9894             // dom node is null, definitely garbage
9895             // -------------------------------------------------------
9896             // !d.parentNode
9897             // no parentNode == direct orphan, definitely garbage
9898             // -------------------------------------------------------
9899             // !d.offsetParent && !document.getElementById(eid)
9900             // display none elements have no offsetParent so we will
9901             // also try to look it up by it's id. However, check
9902             // offsetParent first so we don't do unneeded lookups.
9903             // This enables collection of elements that are not orphans
9904             // directly, but somewhere up the line they have an orphan
9905             // parent.
9906             // -------------------------------------------------------
9907             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9908                 delete El.cache[eid];
9909                 if(d && Roo.enableListenerCollection){
9910                     E.purgeElement(d);
9911                 }
9912             }
9913         }
9914     }
9915     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9916
9917
9918     // dom is optional
9919     El.Flyweight = function(dom){
9920         this.dom = dom;
9921     };
9922     El.Flyweight.prototype = El.prototype;
9923
9924     El._flyweights = {};
9925     /**
9926      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9927      * the dom node can be overwritten by other code.
9928      * @param {String/HTMLElement} el The dom node or id
9929      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9930      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9931      * @static
9932      * @return {Element} The shared Element object
9933      */
9934     El.fly = function(el, named){
9935         named = named || '_global';
9936         el = Roo.getDom(el);
9937         if(!el){
9938             return null;
9939         }
9940         if(!El._flyweights[named]){
9941             El._flyweights[named] = new El.Flyweight();
9942         }
9943         El._flyweights[named].dom = el;
9944         return El._flyweights[named];
9945     };
9946
9947     /**
9948      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9949      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9950      * Shorthand of {@link Roo.Element#get}
9951      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9952      * @return {Element} The Element object
9953      * @member Roo
9954      * @method get
9955      */
9956     Roo.get = El.get;
9957     /**
9958      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9959      * the dom node can be overwritten by other code.
9960      * Shorthand of {@link Roo.Element#fly}
9961      * @param {String/HTMLElement} el The dom node or id
9962      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9963      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9964      * @static
9965      * @return {Element} The shared Element object
9966      * @member Roo
9967      * @method fly
9968      */
9969     Roo.fly = El.fly;
9970
9971     // speedy lookup for elements never to box adjust
9972     var noBoxAdjust = Roo.isStrict ? {
9973         select:1
9974     } : {
9975         input:1, select:1, textarea:1
9976     };
9977     if(Roo.isIE || Roo.isGecko){
9978         noBoxAdjust['button'] = 1;
9979     }
9980
9981
9982     Roo.EventManager.on(window, 'unload', function(){
9983         delete El.cache;
9984         delete El._flyweights;
9985     });
9986 })();
9987
9988
9989
9990
9991 if(Roo.DomQuery){
9992     Roo.Element.selectorFunction = Roo.DomQuery.select;
9993 }
9994
9995 Roo.Element.select = function(selector, unique, root){
9996     var els;
9997     if(typeof selector == "string"){
9998         els = Roo.Element.selectorFunction(selector, root);
9999     }else if(selector.length !== undefined){
10000         els = selector;
10001     }else{
10002         throw "Invalid selector";
10003     }
10004     if(unique === true){
10005         return new Roo.CompositeElement(els);
10006     }else{
10007         return new Roo.CompositeElementLite(els);
10008     }
10009 };
10010 /**
10011  * Selects elements based on the passed CSS selector to enable working on them as 1.
10012  * @param {String/Array} selector The CSS selector or an array of elements
10013  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10014  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10015  * @return {CompositeElementLite/CompositeElement}
10016  * @member Roo
10017  * @method select
10018  */
10019 Roo.select = Roo.Element.select;
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
10030
10031
10032
10033
10034 /*
10035  * Based on:
10036  * Ext JS Library 1.1.1
10037  * Copyright(c) 2006-2007, Ext JS, LLC.
10038  *
10039  * Originally Released Under LGPL - original licence link has changed is not relivant.
10040  *
10041  * Fork - LGPL
10042  * <script type="text/javascript">
10043  */
10044
10045
10046
10047 //Notifies Element that fx methods are available
10048 Roo.enableFx = true;
10049
10050 /**
10051  * @class Roo.Fx
10052  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10053  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10054  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10055  * Element effects to work.</p><br/>
10056  *
10057  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10058  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10059  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10060  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10061  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10062  * expected results and should be done with care.</p><br/>
10063  *
10064  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10065  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10066 <pre>
10067 Value  Description
10068 -----  -----------------------------
10069 tl     The top left corner
10070 t      The center of the top edge
10071 tr     The top right corner
10072 l      The center of the left edge
10073 r      The center of the right edge
10074 bl     The bottom left corner
10075 b      The center of the bottom edge
10076 br     The bottom right corner
10077 </pre>
10078  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10079  * below are common options that can be passed to any Fx method.</b>
10080  * @cfg {Function} callback A function called when the effect is finished
10081  * @cfg {Object} scope The scope of the effect function
10082  * @cfg {String} easing A valid Easing value for the effect
10083  * @cfg {String} afterCls A css class to apply after the effect
10084  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10085  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10086  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10087  * effects that end with the element being visually hidden, ignored otherwise)
10088  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10089  * a function which returns such a specification that will be applied to the Element after the effect finishes
10090  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10091  * @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
10092  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10093  */
10094 Roo.Fx = {
10095         /**
10096          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10097          * origin for the slide effect.  This function automatically handles wrapping the element with
10098          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10099          * Usage:
10100          *<pre><code>
10101 // default: slide the element in from the top
10102 el.slideIn();
10103
10104 // custom: slide the element in from the right with a 2-second duration
10105 el.slideIn('r', { duration: 2 });
10106
10107 // common config options shown with default values
10108 el.slideIn('t', {
10109     easing: 'easeOut',
10110     duration: .5
10111 });
10112 </code></pre>
10113          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10114          * @param {Object} options (optional) Object literal with any of the Fx config options
10115          * @return {Roo.Element} The Element
10116          */
10117     slideIn : function(anchor, o){
10118         var el = this.getFxEl();
10119         o = o || {};
10120
10121         el.queueFx(o, function(){
10122
10123             anchor = anchor || "t";
10124
10125             // fix display to visibility
10126             this.fixDisplay();
10127
10128             // restore values after effect
10129             var r = this.getFxRestore();
10130             var b = this.getBox();
10131             // fixed size for slide
10132             this.setSize(b);
10133
10134             // wrap if needed
10135             var wrap = this.fxWrap(r.pos, o, "hidden");
10136
10137             var st = this.dom.style;
10138             st.visibility = "visible";
10139             st.position = "absolute";
10140
10141             // clear out temp styles after slide and unwrap
10142             var after = function(){
10143                 el.fxUnwrap(wrap, r.pos, o);
10144                 st.width = r.width;
10145                 st.height = r.height;
10146                 el.afterFx(o);
10147             };
10148             // time to calc the positions
10149             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10150
10151             switch(anchor.toLowerCase()){
10152                 case "t":
10153                     wrap.setSize(b.width, 0);
10154                     st.left = st.bottom = "0";
10155                     a = {height: bh};
10156                 break;
10157                 case "l":
10158                     wrap.setSize(0, b.height);
10159                     st.right = st.top = "0";
10160                     a = {width: bw};
10161                 break;
10162                 case "r":
10163                     wrap.setSize(0, b.height);
10164                     wrap.setX(b.right);
10165                     st.left = st.top = "0";
10166                     a = {width: bw, points: pt};
10167                 break;
10168                 case "b":
10169                     wrap.setSize(b.width, 0);
10170                     wrap.setY(b.bottom);
10171                     st.left = st.top = "0";
10172                     a = {height: bh, points: pt};
10173                 break;
10174                 case "tl":
10175                     wrap.setSize(0, 0);
10176                     st.right = st.bottom = "0";
10177                     a = {width: bw, height: bh};
10178                 break;
10179                 case "bl":
10180                     wrap.setSize(0, 0);
10181                     wrap.setY(b.y+b.height);
10182                     st.right = st.top = "0";
10183                     a = {width: bw, height: bh, points: pt};
10184                 break;
10185                 case "br":
10186                     wrap.setSize(0, 0);
10187                     wrap.setXY([b.right, b.bottom]);
10188                     st.left = st.top = "0";
10189                     a = {width: bw, height: bh, points: pt};
10190                 break;
10191                 case "tr":
10192                     wrap.setSize(0, 0);
10193                     wrap.setX(b.x+b.width);
10194                     st.left = st.bottom = "0";
10195                     a = {width: bw, height: bh, points: pt};
10196                 break;
10197             }
10198             this.dom.style.visibility = "visible";
10199             wrap.show();
10200
10201             arguments.callee.anim = wrap.fxanim(a,
10202                 o,
10203                 'motion',
10204                 .5,
10205                 'easeOut', after);
10206         });
10207         return this;
10208     },
10209     
10210         /**
10211          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10212          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10213          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10214          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10215          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10216          * Usage:
10217          *<pre><code>
10218 // default: slide the element out to the top
10219 el.slideOut();
10220
10221 // custom: slide the element out to the right with a 2-second duration
10222 el.slideOut('r', { duration: 2 });
10223
10224 // common config options shown with default values
10225 el.slideOut('t', {
10226     easing: 'easeOut',
10227     duration: .5,
10228     remove: false,
10229     useDisplay: false
10230 });
10231 </code></pre>
10232          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10233          * @param {Object} options (optional) Object literal with any of the Fx config options
10234          * @return {Roo.Element} The Element
10235          */
10236     slideOut : function(anchor, o){
10237         var el = this.getFxEl();
10238         o = o || {};
10239
10240         el.queueFx(o, function(){
10241
10242             anchor = anchor || "t";
10243
10244             // restore values after effect
10245             var r = this.getFxRestore();
10246             
10247             var b = this.getBox();
10248             // fixed size for slide
10249             this.setSize(b);
10250
10251             // wrap if needed
10252             var wrap = this.fxWrap(r.pos, o, "visible");
10253
10254             var st = this.dom.style;
10255             st.visibility = "visible";
10256             st.position = "absolute";
10257
10258             wrap.setSize(b);
10259
10260             var after = function(){
10261                 if(o.useDisplay){
10262                     el.setDisplayed(false);
10263                 }else{
10264                     el.hide();
10265                 }
10266
10267                 el.fxUnwrap(wrap, r.pos, o);
10268
10269                 st.width = r.width;
10270                 st.height = r.height;
10271
10272                 el.afterFx(o);
10273             };
10274
10275             var a, zero = {to: 0};
10276             switch(anchor.toLowerCase()){
10277                 case "t":
10278                     st.left = st.bottom = "0";
10279                     a = {height: zero};
10280                 break;
10281                 case "l":
10282                     st.right = st.top = "0";
10283                     a = {width: zero};
10284                 break;
10285                 case "r":
10286                     st.left = st.top = "0";
10287                     a = {width: zero, points: {to:[b.right, b.y]}};
10288                 break;
10289                 case "b":
10290                     st.left = st.top = "0";
10291                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10292                 break;
10293                 case "tl":
10294                     st.right = st.bottom = "0";
10295                     a = {width: zero, height: zero};
10296                 break;
10297                 case "bl":
10298                     st.right = st.top = "0";
10299                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10300                 break;
10301                 case "br":
10302                     st.left = st.top = "0";
10303                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10304                 break;
10305                 case "tr":
10306                     st.left = st.bottom = "0";
10307                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10308                 break;
10309             }
10310
10311             arguments.callee.anim = wrap.fxanim(a,
10312                 o,
10313                 'motion',
10314                 .5,
10315                 "easeOut", after);
10316         });
10317         return this;
10318     },
10319
10320         /**
10321          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10322          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10323          * The element must be removed from the DOM using the 'remove' config option if desired.
10324          * Usage:
10325          *<pre><code>
10326 // default
10327 el.puff();
10328
10329 // common config options shown with default values
10330 el.puff({
10331     easing: 'easeOut',
10332     duration: .5,
10333     remove: false,
10334     useDisplay: false
10335 });
10336 </code></pre>
10337          * @param {Object} options (optional) Object literal with any of the Fx config options
10338          * @return {Roo.Element} The Element
10339          */
10340     puff : function(o){
10341         var el = this.getFxEl();
10342         o = o || {};
10343
10344         el.queueFx(o, function(){
10345             this.clearOpacity();
10346             this.show();
10347
10348             // restore values after effect
10349             var r = this.getFxRestore();
10350             var st = this.dom.style;
10351
10352             var after = function(){
10353                 if(o.useDisplay){
10354                     el.setDisplayed(false);
10355                 }else{
10356                     el.hide();
10357                 }
10358
10359                 el.clearOpacity();
10360
10361                 el.setPositioning(r.pos);
10362                 st.width = r.width;
10363                 st.height = r.height;
10364                 st.fontSize = '';
10365                 el.afterFx(o);
10366             };
10367
10368             var width = this.getWidth();
10369             var height = this.getHeight();
10370
10371             arguments.callee.anim = this.fxanim({
10372                     width : {to: this.adjustWidth(width * 2)},
10373                     height : {to: this.adjustHeight(height * 2)},
10374                     points : {by: [-(width * .5), -(height * .5)]},
10375                     opacity : {to: 0},
10376                     fontSize: {to:200, unit: "%"}
10377                 },
10378                 o,
10379                 'motion',
10380                 .5,
10381                 "easeOut", after);
10382         });
10383         return this;
10384     },
10385
10386         /**
10387          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10388          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10389          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10390          * Usage:
10391          *<pre><code>
10392 // default
10393 el.switchOff();
10394
10395 // all config options shown with default values
10396 el.switchOff({
10397     easing: 'easeIn',
10398     duration: .3,
10399     remove: false,
10400     useDisplay: false
10401 });
10402 </code></pre>
10403          * @param {Object} options (optional) Object literal with any of the Fx config options
10404          * @return {Roo.Element} The Element
10405          */
10406     switchOff : function(o){
10407         var el = this.getFxEl();
10408         o = o || {};
10409
10410         el.queueFx(o, function(){
10411             this.clearOpacity();
10412             this.clip();
10413
10414             // restore values after effect
10415             var r = this.getFxRestore();
10416             var st = this.dom.style;
10417
10418             var after = function(){
10419                 if(o.useDisplay){
10420                     el.setDisplayed(false);
10421                 }else{
10422                     el.hide();
10423                 }
10424
10425                 el.clearOpacity();
10426                 el.setPositioning(r.pos);
10427                 st.width = r.width;
10428                 st.height = r.height;
10429
10430                 el.afterFx(o);
10431             };
10432
10433             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10434                 this.clearOpacity();
10435                 (function(){
10436                     this.fxanim({
10437                         height:{to:1},
10438                         points:{by:[0, this.getHeight() * .5]}
10439                     }, o, 'motion', 0.3, 'easeIn', after);
10440                 }).defer(100, this);
10441             });
10442         });
10443         return this;
10444     },
10445
10446     /**
10447      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10448      * changed using the "attr" config option) and then fading back to the original color. If no original
10449      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10450      * Usage:
10451 <pre><code>
10452 // default: highlight background to yellow
10453 el.highlight();
10454
10455 // custom: highlight foreground text to blue for 2 seconds
10456 el.highlight("0000ff", { attr: 'color', duration: 2 });
10457
10458 // common config options shown with default values
10459 el.highlight("ffff9c", {
10460     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10461     endColor: (current color) or "ffffff",
10462     easing: 'easeIn',
10463     duration: 1
10464 });
10465 </code></pre>
10466      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10467      * @param {Object} options (optional) Object literal with any of the Fx config options
10468      * @return {Roo.Element} The Element
10469      */ 
10470     highlight : function(color, o){
10471         var el = this.getFxEl();
10472         o = o || {};
10473
10474         el.queueFx(o, function(){
10475             color = color || "ffff9c";
10476             attr = o.attr || "backgroundColor";
10477
10478             this.clearOpacity();
10479             this.show();
10480
10481             var origColor = this.getColor(attr);
10482             var restoreColor = this.dom.style[attr];
10483             endColor = (o.endColor || origColor) || "ffffff";
10484
10485             var after = function(){
10486                 el.dom.style[attr] = restoreColor;
10487                 el.afterFx(o);
10488             };
10489
10490             var a = {};
10491             a[attr] = {from: color, to: endColor};
10492             arguments.callee.anim = this.fxanim(a,
10493                 o,
10494                 'color',
10495                 1,
10496                 'easeIn', after);
10497         });
10498         return this;
10499     },
10500
10501    /**
10502     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10503     * Usage:
10504 <pre><code>
10505 // default: a single light blue ripple
10506 el.frame();
10507
10508 // custom: 3 red ripples lasting 3 seconds total
10509 el.frame("ff0000", 3, { duration: 3 });
10510
10511 // common config options shown with default values
10512 el.frame("C3DAF9", 1, {
10513     duration: 1 //duration of entire animation (not each individual ripple)
10514     // Note: Easing is not configurable and will be ignored if included
10515 });
10516 </code></pre>
10517     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10518     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10519     * @param {Object} options (optional) Object literal with any of the Fx config options
10520     * @return {Roo.Element} The Element
10521     */
10522     frame : function(color, count, o){
10523         var el = this.getFxEl();
10524         o = o || {};
10525
10526         el.queueFx(o, function(){
10527             color = color || "#C3DAF9";
10528             if(color.length == 6){
10529                 color = "#" + color;
10530             }
10531             count = count || 1;
10532             duration = o.duration || 1;
10533             this.show();
10534
10535             var b = this.getBox();
10536             var animFn = function(){
10537                 var proxy = this.createProxy({
10538
10539                      style:{
10540                         visbility:"hidden",
10541                         position:"absolute",
10542                         "z-index":"35000", // yee haw
10543                         border:"0px solid " + color
10544                      }
10545                   });
10546                 var scale = Roo.isBorderBox ? 2 : 1;
10547                 proxy.animate({
10548                     top:{from:b.y, to:b.y - 20},
10549                     left:{from:b.x, to:b.x - 20},
10550                     borderWidth:{from:0, to:10},
10551                     opacity:{from:1, to:0},
10552                     height:{from:b.height, to:(b.height + (20*scale))},
10553                     width:{from:b.width, to:(b.width + (20*scale))}
10554                 }, duration, function(){
10555                     proxy.remove();
10556                 });
10557                 if(--count > 0){
10558                      animFn.defer((duration/2)*1000, this);
10559                 }else{
10560                     el.afterFx(o);
10561                 }
10562             };
10563             animFn.call(this);
10564         });
10565         return this;
10566     },
10567
10568    /**
10569     * Creates a pause before any subsequent queued effects begin.  If there are
10570     * no effects queued after the pause it will have no effect.
10571     * Usage:
10572 <pre><code>
10573 el.pause(1);
10574 </code></pre>
10575     * @param {Number} seconds The length of time to pause (in seconds)
10576     * @return {Roo.Element} The Element
10577     */
10578     pause : function(seconds){
10579         var el = this.getFxEl();
10580         var o = {};
10581
10582         el.queueFx(o, function(){
10583             setTimeout(function(){
10584                 el.afterFx(o);
10585             }, seconds * 1000);
10586         });
10587         return this;
10588     },
10589
10590    /**
10591     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10592     * using the "endOpacity" config option.
10593     * Usage:
10594 <pre><code>
10595 // default: fade in from opacity 0 to 100%
10596 el.fadeIn();
10597
10598 // custom: fade in from opacity 0 to 75% over 2 seconds
10599 el.fadeIn({ endOpacity: .75, duration: 2});
10600
10601 // common config options shown with default values
10602 el.fadeIn({
10603     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10604     easing: 'easeOut',
10605     duration: .5
10606 });
10607 </code></pre>
10608     * @param {Object} options (optional) Object literal with any of the Fx config options
10609     * @return {Roo.Element} The Element
10610     */
10611     fadeIn : function(o){
10612         var el = this.getFxEl();
10613         o = o || {};
10614         el.queueFx(o, function(){
10615             this.setOpacity(0);
10616             this.fixDisplay();
10617             this.dom.style.visibility = 'visible';
10618             var to = o.endOpacity || 1;
10619             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10620                 o, null, .5, "easeOut", function(){
10621                 if(to == 1){
10622                     this.clearOpacity();
10623                 }
10624                 el.afterFx(o);
10625             });
10626         });
10627         return this;
10628     },
10629
10630    /**
10631     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10632     * using the "endOpacity" config option.
10633     * Usage:
10634 <pre><code>
10635 // default: fade out from the element's current opacity to 0
10636 el.fadeOut();
10637
10638 // custom: fade out from the element's current opacity to 25% over 2 seconds
10639 el.fadeOut({ endOpacity: .25, duration: 2});
10640
10641 // common config options shown with default values
10642 el.fadeOut({
10643     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10644     easing: 'easeOut',
10645     duration: .5
10646     remove: false,
10647     useDisplay: false
10648 });
10649 </code></pre>
10650     * @param {Object} options (optional) Object literal with any of the Fx config options
10651     * @return {Roo.Element} The Element
10652     */
10653     fadeOut : function(o){
10654         var el = this.getFxEl();
10655         o = o || {};
10656         el.queueFx(o, function(){
10657             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10658                 o, null, .5, "easeOut", function(){
10659                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10660                      this.dom.style.display = "none";
10661                 }else{
10662                      this.dom.style.visibility = "hidden";
10663                 }
10664                 this.clearOpacity();
10665                 el.afterFx(o);
10666             });
10667         });
10668         return this;
10669     },
10670
10671    /**
10672     * Animates the transition of an element's dimensions from a starting height/width
10673     * to an ending height/width.
10674     * Usage:
10675 <pre><code>
10676 // change height and width to 100x100 pixels
10677 el.scale(100, 100);
10678
10679 // common config options shown with default values.  The height and width will default to
10680 // the element's existing values if passed as null.
10681 el.scale(
10682     [element's width],
10683     [element's height], {
10684     easing: 'easeOut',
10685     duration: .35
10686 });
10687 </code></pre>
10688     * @param {Number} width  The new width (pass undefined to keep the original width)
10689     * @param {Number} height  The new height (pass undefined to keep the original height)
10690     * @param {Object} options (optional) Object literal with any of the Fx config options
10691     * @return {Roo.Element} The Element
10692     */
10693     scale : function(w, h, o){
10694         this.shift(Roo.apply({}, o, {
10695             width: w,
10696             height: h
10697         }));
10698         return this;
10699     },
10700
10701    /**
10702     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10703     * Any of these properties not specified in the config object will not be changed.  This effect 
10704     * requires that at least one new dimension, position or opacity setting must be passed in on
10705     * the config object in order for the function to have any effect.
10706     * Usage:
10707 <pre><code>
10708 // slide the element horizontally to x position 200 while changing the height and opacity
10709 el.shift({ x: 200, height: 50, opacity: .8 });
10710
10711 // common config options shown with default values.
10712 el.shift({
10713     width: [element's width],
10714     height: [element's height],
10715     x: [element's x position],
10716     y: [element's y position],
10717     opacity: [element's opacity],
10718     easing: 'easeOut',
10719     duration: .35
10720 });
10721 </code></pre>
10722     * @param {Object} options  Object literal with any of the Fx config options
10723     * @return {Roo.Element} The Element
10724     */
10725     shift : function(o){
10726         var el = this.getFxEl();
10727         o = o || {};
10728         el.queueFx(o, function(){
10729             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10730             if(w !== undefined){
10731                 a.width = {to: this.adjustWidth(w)};
10732             }
10733             if(h !== undefined){
10734                 a.height = {to: this.adjustHeight(h)};
10735             }
10736             if(x !== undefined || y !== undefined){
10737                 a.points = {to: [
10738                     x !== undefined ? x : this.getX(),
10739                     y !== undefined ? y : this.getY()
10740                 ]};
10741             }
10742             if(op !== undefined){
10743                 a.opacity = {to: op};
10744             }
10745             if(o.xy !== undefined){
10746                 a.points = {to: o.xy};
10747             }
10748             arguments.callee.anim = this.fxanim(a,
10749                 o, 'motion', .35, "easeOut", function(){
10750                 el.afterFx(o);
10751             });
10752         });
10753         return this;
10754     },
10755
10756         /**
10757          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10758          * ending point of the effect.
10759          * Usage:
10760          *<pre><code>
10761 // default: slide the element downward while fading out
10762 el.ghost();
10763
10764 // custom: slide the element out to the right with a 2-second duration
10765 el.ghost('r', { duration: 2 });
10766
10767 // common config options shown with default values
10768 el.ghost('b', {
10769     easing: 'easeOut',
10770     duration: .5
10771     remove: false,
10772     useDisplay: false
10773 });
10774 </code></pre>
10775          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10776          * @param {Object} options (optional) Object literal with any of the Fx config options
10777          * @return {Roo.Element} The Element
10778          */
10779     ghost : function(anchor, o){
10780         var el = this.getFxEl();
10781         o = o || {};
10782
10783         el.queueFx(o, function(){
10784             anchor = anchor || "b";
10785
10786             // restore values after effect
10787             var r = this.getFxRestore();
10788             var w = this.getWidth(),
10789                 h = this.getHeight();
10790
10791             var st = this.dom.style;
10792
10793             var after = function(){
10794                 if(o.useDisplay){
10795                     el.setDisplayed(false);
10796                 }else{
10797                     el.hide();
10798                 }
10799
10800                 el.clearOpacity();
10801                 el.setPositioning(r.pos);
10802                 st.width = r.width;
10803                 st.height = r.height;
10804
10805                 el.afterFx(o);
10806             };
10807
10808             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10809             switch(anchor.toLowerCase()){
10810                 case "t":
10811                     pt.by = [0, -h];
10812                 break;
10813                 case "l":
10814                     pt.by = [-w, 0];
10815                 break;
10816                 case "r":
10817                     pt.by = [w, 0];
10818                 break;
10819                 case "b":
10820                     pt.by = [0, h];
10821                 break;
10822                 case "tl":
10823                     pt.by = [-w, -h];
10824                 break;
10825                 case "bl":
10826                     pt.by = [-w, h];
10827                 break;
10828                 case "br":
10829                     pt.by = [w, h];
10830                 break;
10831                 case "tr":
10832                     pt.by = [w, -h];
10833                 break;
10834             }
10835
10836             arguments.callee.anim = this.fxanim(a,
10837                 o,
10838                 'motion',
10839                 .5,
10840                 "easeOut", after);
10841         });
10842         return this;
10843     },
10844
10845         /**
10846          * Ensures that all effects queued after syncFx is called on the element are
10847          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10848          * @return {Roo.Element} The Element
10849          */
10850     syncFx : function(){
10851         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10852             block : false,
10853             concurrent : true,
10854             stopFx : false
10855         });
10856         return this;
10857     },
10858
10859         /**
10860          * Ensures that all effects queued after sequenceFx is called on the element are
10861          * run in sequence.  This is the opposite of {@link #syncFx}.
10862          * @return {Roo.Element} The Element
10863          */
10864     sequenceFx : function(){
10865         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10866             block : false,
10867             concurrent : false,
10868             stopFx : false
10869         });
10870         return this;
10871     },
10872
10873         /* @private */
10874     nextFx : function(){
10875         var ef = this.fxQueue[0];
10876         if(ef){
10877             ef.call(this);
10878         }
10879     },
10880
10881         /**
10882          * Returns true if the element has any effects actively running or queued, else returns false.
10883          * @return {Boolean} True if element has active effects, else false
10884          */
10885     hasActiveFx : function(){
10886         return this.fxQueue && this.fxQueue[0];
10887     },
10888
10889         /**
10890          * Stops any running effects and clears the element's internal effects queue if it contains
10891          * any additional effects that haven't started yet.
10892          * @return {Roo.Element} The Element
10893          */
10894     stopFx : function(){
10895         if(this.hasActiveFx()){
10896             var cur = this.fxQueue[0];
10897             if(cur && cur.anim && cur.anim.isAnimated()){
10898                 this.fxQueue = [cur]; // clear out others
10899                 cur.anim.stop(true);
10900             }
10901         }
10902         return this;
10903     },
10904
10905         /* @private */
10906     beforeFx : function(o){
10907         if(this.hasActiveFx() && !o.concurrent){
10908            if(o.stopFx){
10909                this.stopFx();
10910                return true;
10911            }
10912            return false;
10913         }
10914         return true;
10915     },
10916
10917         /**
10918          * Returns true if the element is currently blocking so that no other effect can be queued
10919          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10920          * used to ensure that an effect initiated by a user action runs to completion prior to the
10921          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10922          * @return {Boolean} True if blocking, else false
10923          */
10924     hasFxBlock : function(){
10925         var q = this.fxQueue;
10926         return q && q[0] && q[0].block;
10927     },
10928
10929         /* @private */
10930     queueFx : function(o, fn){
10931         if(!this.fxQueue){
10932             this.fxQueue = [];
10933         }
10934         if(!this.hasFxBlock()){
10935             Roo.applyIf(o, this.fxDefaults);
10936             if(!o.concurrent){
10937                 var run = this.beforeFx(o);
10938                 fn.block = o.block;
10939                 this.fxQueue.push(fn);
10940                 if(run){
10941                     this.nextFx();
10942                 }
10943             }else{
10944                 fn.call(this);
10945             }
10946         }
10947         return this;
10948     },
10949
10950         /* @private */
10951     fxWrap : function(pos, o, vis){
10952         var wrap;
10953         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10954             var wrapXY;
10955             if(o.fixPosition){
10956                 wrapXY = this.getXY();
10957             }
10958             var div = document.createElement("div");
10959             div.style.visibility = vis;
10960             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10961             wrap.setPositioning(pos);
10962             if(wrap.getStyle("position") == "static"){
10963                 wrap.position("relative");
10964             }
10965             this.clearPositioning('auto');
10966             wrap.clip();
10967             wrap.dom.appendChild(this.dom);
10968             if(wrapXY){
10969                 wrap.setXY(wrapXY);
10970             }
10971         }
10972         return wrap;
10973     },
10974
10975         /* @private */
10976     fxUnwrap : function(wrap, pos, o){
10977         this.clearPositioning();
10978         this.setPositioning(pos);
10979         if(!o.wrap){
10980             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10981             wrap.remove();
10982         }
10983     },
10984
10985         /* @private */
10986     getFxRestore : function(){
10987         var st = this.dom.style;
10988         return {pos: this.getPositioning(), width: st.width, height : st.height};
10989     },
10990
10991         /* @private */
10992     afterFx : function(o){
10993         if(o.afterStyle){
10994             this.applyStyles(o.afterStyle);
10995         }
10996         if(o.afterCls){
10997             this.addClass(o.afterCls);
10998         }
10999         if(o.remove === true){
11000             this.remove();
11001         }
11002         Roo.callback(o.callback, o.scope, [this]);
11003         if(!o.concurrent){
11004             this.fxQueue.shift();
11005             this.nextFx();
11006         }
11007     },
11008
11009         /* @private */
11010     getFxEl : function(){ // support for composite element fx
11011         return Roo.get(this.dom);
11012     },
11013
11014         /* @private */
11015     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11016         animType = animType || 'run';
11017         opt = opt || {};
11018         var anim = Roo.lib.Anim[animType](
11019             this.dom, args,
11020             (opt.duration || defaultDur) || .35,
11021             (opt.easing || defaultEase) || 'easeOut',
11022             function(){
11023                 Roo.callback(cb, this);
11024             },
11025             this
11026         );
11027         opt.anim = anim;
11028         return anim;
11029     }
11030 };
11031
11032 // backwords compat
11033 Roo.Fx.resize = Roo.Fx.scale;
11034
11035 //When included, Roo.Fx is automatically applied to Element so that all basic
11036 //effects are available directly via the Element API
11037 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11038  * Based on:
11039  * Ext JS Library 1.1.1
11040  * Copyright(c) 2006-2007, Ext JS, LLC.
11041  *
11042  * Originally Released Under LGPL - original licence link has changed is not relivant.
11043  *
11044  * Fork - LGPL
11045  * <script type="text/javascript">
11046  */
11047
11048
11049 /**
11050  * @class Roo.CompositeElement
11051  * Standard composite class. Creates a Roo.Element for every element in the collection.
11052  * <br><br>
11053  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11054  * actions will be performed on all the elements in this collection.</b>
11055  * <br><br>
11056  * All methods return <i>this</i> and can be chained.
11057  <pre><code>
11058  var els = Roo.select("#some-el div.some-class", true);
11059  // or select directly from an existing element
11060  var el = Roo.get('some-el');
11061  el.select('div.some-class', true);
11062
11063  els.setWidth(100); // all elements become 100 width
11064  els.hide(true); // all elements fade out and hide
11065  // or
11066  els.setWidth(100).hide(true);
11067  </code></pre>
11068  */
11069 Roo.CompositeElement = function(els){
11070     this.elements = [];
11071     this.addElements(els);
11072 };
11073 Roo.CompositeElement.prototype = {
11074     isComposite: true,
11075     addElements : function(els){
11076         if(!els) {
11077             return this;
11078         }
11079         if(typeof els == "string"){
11080             els = Roo.Element.selectorFunction(els);
11081         }
11082         var yels = this.elements;
11083         var index = yels.length-1;
11084         for(var i = 0, len = els.length; i < len; i++) {
11085                 yels[++index] = Roo.get(els[i]);
11086         }
11087         return this;
11088     },
11089
11090     /**
11091     * Clears this composite and adds the elements returned by the passed selector.
11092     * @param {String/Array} els A string CSS selector, an array of elements or an element
11093     * @return {CompositeElement} this
11094     */
11095     fill : function(els){
11096         this.elements = [];
11097         this.add(els);
11098         return this;
11099     },
11100
11101     /**
11102     * Filters this composite to only elements that match the passed selector.
11103     * @param {String} selector A string CSS selector
11104     * @param {Boolean} inverse return inverse filter (not matches)
11105     * @return {CompositeElement} this
11106     */
11107     filter : function(selector, inverse){
11108         var els = [];
11109         inverse = inverse || false;
11110         this.each(function(el){
11111             var match = inverse ? !el.is(selector) : el.is(selector);
11112             if(match){
11113                 els[els.length] = el.dom;
11114             }
11115         });
11116         this.fill(els);
11117         return this;
11118     },
11119
11120     invoke : function(fn, args){
11121         var els = this.elements;
11122         for(var i = 0, len = els.length; i < len; i++) {
11123                 Roo.Element.prototype[fn].apply(els[i], args);
11124         }
11125         return this;
11126     },
11127     /**
11128     * Adds elements to this composite.
11129     * @param {String/Array} els A string CSS selector, an array of elements or an element
11130     * @return {CompositeElement} this
11131     */
11132     add : function(els){
11133         if(typeof els == "string"){
11134             this.addElements(Roo.Element.selectorFunction(els));
11135         }else if(els.length !== undefined){
11136             this.addElements(els);
11137         }else{
11138             this.addElements([els]);
11139         }
11140         return this;
11141     },
11142     /**
11143     * Calls the passed function passing (el, this, index) for each element in this composite.
11144     * @param {Function} fn The function to call
11145     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11146     * @return {CompositeElement} this
11147     */
11148     each : function(fn, scope){
11149         var els = this.elements;
11150         for(var i = 0, len = els.length; i < len; i++){
11151             if(fn.call(scope || els[i], els[i], this, i) === false) {
11152                 break;
11153             }
11154         }
11155         return this;
11156     },
11157
11158     /**
11159      * Returns the Element object at the specified index
11160      * @param {Number} index
11161      * @return {Roo.Element}
11162      */
11163     item : function(index){
11164         return this.elements[index] || null;
11165     },
11166
11167     /**
11168      * Returns the first Element
11169      * @return {Roo.Element}
11170      */
11171     first : function(){
11172         return this.item(0);
11173     },
11174
11175     /**
11176      * Returns the last Element
11177      * @return {Roo.Element}
11178      */
11179     last : function(){
11180         return this.item(this.elements.length-1);
11181     },
11182
11183     /**
11184      * Returns the number of elements in this composite
11185      * @return Number
11186      */
11187     getCount : function(){
11188         return this.elements.length;
11189     },
11190
11191     /**
11192      * Returns true if this composite contains the passed element
11193      * @return Boolean
11194      */
11195     contains : function(el){
11196         return this.indexOf(el) !== -1;
11197     },
11198
11199     /**
11200      * Returns true if this composite contains the passed element
11201      * @return Boolean
11202      */
11203     indexOf : function(el){
11204         return this.elements.indexOf(Roo.get(el));
11205     },
11206
11207
11208     /**
11209     * Removes the specified element(s).
11210     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11211     * or an array of any of those.
11212     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11213     * @return {CompositeElement} this
11214     */
11215     removeElement : function(el, removeDom){
11216         if(el instanceof Array){
11217             for(var i = 0, len = el.length; i < len; i++){
11218                 this.removeElement(el[i]);
11219             }
11220             return this;
11221         }
11222         var index = typeof el == 'number' ? el : this.indexOf(el);
11223         if(index !== -1){
11224             if(removeDom){
11225                 var d = this.elements[index];
11226                 if(d.dom){
11227                     d.remove();
11228                 }else{
11229                     d.parentNode.removeChild(d);
11230                 }
11231             }
11232             this.elements.splice(index, 1);
11233         }
11234         return this;
11235     },
11236
11237     /**
11238     * Replaces the specified element with the passed element.
11239     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11240     * to replace.
11241     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11242     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11243     * @return {CompositeElement} this
11244     */
11245     replaceElement : function(el, replacement, domReplace){
11246         var index = typeof el == 'number' ? el : this.indexOf(el);
11247         if(index !== -1){
11248             if(domReplace){
11249                 this.elements[index].replaceWith(replacement);
11250             }else{
11251                 this.elements.splice(index, 1, Roo.get(replacement))
11252             }
11253         }
11254         return this;
11255     },
11256
11257     /**
11258      * Removes all elements.
11259      */
11260     clear : function(){
11261         this.elements = [];
11262     }
11263 };
11264 (function(){
11265     Roo.CompositeElement.createCall = function(proto, fnName){
11266         if(!proto[fnName]){
11267             proto[fnName] = function(){
11268                 return this.invoke(fnName, arguments);
11269             };
11270         }
11271     };
11272     for(var fnName in Roo.Element.prototype){
11273         if(typeof Roo.Element.prototype[fnName] == "function"){
11274             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11275         }
11276     };
11277 })();
11278 /*
11279  * Based on:
11280  * Ext JS Library 1.1.1
11281  * Copyright(c) 2006-2007, Ext JS, LLC.
11282  *
11283  * Originally Released Under LGPL - original licence link has changed is not relivant.
11284  *
11285  * Fork - LGPL
11286  * <script type="text/javascript">
11287  */
11288
11289 /**
11290  * @class Roo.CompositeElementLite
11291  * @extends Roo.CompositeElement
11292  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11293  <pre><code>
11294  var els = Roo.select("#some-el div.some-class");
11295  // or select directly from an existing element
11296  var el = Roo.get('some-el');
11297  el.select('div.some-class');
11298
11299  els.setWidth(100); // all elements become 100 width
11300  els.hide(true); // all elements fade out and hide
11301  // or
11302  els.setWidth(100).hide(true);
11303  </code></pre><br><br>
11304  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11305  * actions will be performed on all the elements in this collection.</b>
11306  */
11307 Roo.CompositeElementLite = function(els){
11308     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11309     this.el = new Roo.Element.Flyweight();
11310 };
11311 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11312     addElements : function(els){
11313         if(els){
11314             if(els instanceof Array){
11315                 this.elements = this.elements.concat(els);
11316             }else{
11317                 var yels = this.elements;
11318                 var index = yels.length-1;
11319                 for(var i = 0, len = els.length; i < len; i++) {
11320                     yels[++index] = els[i];
11321                 }
11322             }
11323         }
11324         return this;
11325     },
11326     invoke : function(fn, args){
11327         var els = this.elements;
11328         var el = this.el;
11329         for(var i = 0, len = els.length; i < len; i++) {
11330             el.dom = els[i];
11331                 Roo.Element.prototype[fn].apply(el, args);
11332         }
11333         return this;
11334     },
11335     /**
11336      * Returns a flyweight Element of the dom element object at the specified index
11337      * @param {Number} index
11338      * @return {Roo.Element}
11339      */
11340     item : function(index){
11341         if(!this.elements[index]){
11342             return null;
11343         }
11344         this.el.dom = this.elements[index];
11345         return this.el;
11346     },
11347
11348     // fixes scope with flyweight
11349     addListener : function(eventName, handler, scope, opt){
11350         var els = this.elements;
11351         for(var i = 0, len = els.length; i < len; i++) {
11352             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11353         }
11354         return this;
11355     },
11356
11357     /**
11358     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11359     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11360     * a reference to the dom node, use el.dom.</b>
11361     * @param {Function} fn The function to call
11362     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11363     * @return {CompositeElement} this
11364     */
11365     each : function(fn, scope){
11366         var els = this.elements;
11367         var el = this.el;
11368         for(var i = 0, len = els.length; i < len; i++){
11369             el.dom = els[i];
11370                 if(fn.call(scope || el, el, this, i) === false){
11371                 break;
11372             }
11373         }
11374         return this;
11375     },
11376
11377     indexOf : function(el){
11378         return this.elements.indexOf(Roo.getDom(el));
11379     },
11380
11381     replaceElement : function(el, replacement, domReplace){
11382         var index = typeof el == 'number' ? el : this.indexOf(el);
11383         if(index !== -1){
11384             replacement = Roo.getDom(replacement);
11385             if(domReplace){
11386                 var d = this.elements[index];
11387                 d.parentNode.insertBefore(replacement, d);
11388                 d.parentNode.removeChild(d);
11389             }
11390             this.elements.splice(index, 1, replacement);
11391         }
11392         return this;
11393     }
11394 });
11395 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11396
11397 /*
11398  * Based on:
11399  * Ext JS Library 1.1.1
11400  * Copyright(c) 2006-2007, Ext JS, LLC.
11401  *
11402  * Originally Released Under LGPL - original licence link has changed is not relivant.
11403  *
11404  * Fork - LGPL
11405  * <script type="text/javascript">
11406  */
11407
11408  
11409
11410 /**
11411  * @class Roo.data.Connection
11412  * @extends Roo.util.Observable
11413  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11414  * either to a configured URL, or to a URL specified at request time.<br><br>
11415  * <p>
11416  * Requests made by this class are asynchronous, and will return immediately. No data from
11417  * the server will be available to the statement immediately following the {@link #request} call.
11418  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11419  * <p>
11420  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11421  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11422  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11423  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11424  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11425  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11426  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11427  * standard DOM methods.
11428  * @constructor
11429  * @param {Object} config a configuration object.
11430  */
11431 Roo.data.Connection = function(config){
11432     Roo.apply(this, config);
11433     this.addEvents({
11434         /**
11435          * @event beforerequest
11436          * Fires before a network request is made to retrieve a data object.
11437          * @param {Connection} conn This Connection object.
11438          * @param {Object} options The options config object passed to the {@link #request} method.
11439          */
11440         "beforerequest" : true,
11441         /**
11442          * @event requestcomplete
11443          * Fires if the request was successfully completed.
11444          * @param {Connection} conn This Connection object.
11445          * @param {Object} response The XHR object containing the response data.
11446          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11447          * @param {Object} options The options config object passed to the {@link #request} method.
11448          */
11449         "requestcomplete" : true,
11450         /**
11451          * @event requestexception
11452          * Fires if an error HTTP status was returned from the server.
11453          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11454          * @param {Connection} conn This Connection object.
11455          * @param {Object} response The XHR object containing the response data.
11456          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11457          * @param {Object} options The options config object passed to the {@link #request} method.
11458          */
11459         "requestexception" : true
11460     });
11461     Roo.data.Connection.superclass.constructor.call(this);
11462 };
11463
11464 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11465     /**
11466      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11467      */
11468     /**
11469      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11470      * extra parameters to each request made by this object. (defaults to undefined)
11471      */
11472     /**
11473      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11474      *  to each request made by this object. (defaults to undefined)
11475      */
11476     /**
11477      * @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)
11478      */
11479     /**
11480      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11481      */
11482     timeout : 30000,
11483     /**
11484      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11485      * @type Boolean
11486      */
11487     autoAbort:false,
11488
11489     /**
11490      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11491      * @type Boolean
11492      */
11493     disableCaching: true,
11494
11495     /**
11496      * Sends an HTTP request to a remote server.
11497      * @param {Object} options An object which may contain the following properties:<ul>
11498      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11499      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11500      * request, a url encoded string or a function to call to get either.</li>
11501      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11502      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11503      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11504      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11505      * <li>options {Object} The parameter to the request call.</li>
11506      * <li>success {Boolean} True if the request succeeded.</li>
11507      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11508      * </ul></li>
11509      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11510      * The callback is passed the following parameters:<ul>
11511      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11512      * <li>options {Object} The parameter to the request call.</li>
11513      * </ul></li>
11514      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11515      * The callback is passed the following parameters:<ul>
11516      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11517      * <li>options {Object} The parameter to the request call.</li>
11518      * </ul></li>
11519      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11520      * for the callback function. Defaults to the browser window.</li>
11521      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11522      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11523      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11524      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11525      * params for the post data. Any params will be appended to the URL.</li>
11526      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11527      * </ul>
11528      * @return {Number} transactionId
11529      */
11530     request : function(o){
11531         if(this.fireEvent("beforerequest", this, o) !== false){
11532             var p = o.params;
11533
11534             if(typeof p == "function"){
11535                 p = p.call(o.scope||window, o);
11536             }
11537             if(typeof p == "object"){
11538                 p = Roo.urlEncode(o.params);
11539             }
11540             if(this.extraParams){
11541                 var extras = Roo.urlEncode(this.extraParams);
11542                 p = p ? (p + '&' + extras) : extras;
11543             }
11544
11545             var url = o.url || this.url;
11546             if(typeof url == 'function'){
11547                 url = url.call(o.scope||window, o);
11548             }
11549
11550             if(o.form){
11551                 var form = Roo.getDom(o.form);
11552                 url = url || form.action;
11553
11554                 var enctype = form.getAttribute("enctype");
11555                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11556                     return this.doFormUpload(o, p, url);
11557                 }
11558                 var f = Roo.lib.Ajax.serializeForm(form);
11559                 p = p ? (p + '&' + f) : f;
11560             }
11561
11562             var hs = o.headers;
11563             if(this.defaultHeaders){
11564                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11565                 if(!o.headers){
11566                     o.headers = hs;
11567                 }
11568             }
11569
11570             var cb = {
11571                 success: this.handleResponse,
11572                 failure: this.handleFailure,
11573                 scope: this,
11574                 argument: {options: o},
11575                 timeout : o.timeout || this.timeout
11576             };
11577
11578             var method = o.method||this.method||(p ? "POST" : "GET");
11579
11580             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11581                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11582             }
11583
11584             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11585                 if(o.autoAbort){
11586                     this.abort();
11587                 }
11588             }else if(this.autoAbort !== false){
11589                 this.abort();
11590             }
11591
11592             if((method == 'GET' && p) || o.xmlData){
11593                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11594                 p = '';
11595             }
11596             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11597             return this.transId;
11598         }else{
11599             Roo.callback(o.callback, o.scope, [o, null, null]);
11600             return null;
11601         }
11602     },
11603
11604     /**
11605      * Determine whether this object has a request outstanding.
11606      * @param {Number} transactionId (Optional) defaults to the last transaction
11607      * @return {Boolean} True if there is an outstanding request.
11608      */
11609     isLoading : function(transId){
11610         if(transId){
11611             return Roo.lib.Ajax.isCallInProgress(transId);
11612         }else{
11613             return this.transId ? true : false;
11614         }
11615     },
11616
11617     /**
11618      * Aborts any outstanding request.
11619      * @param {Number} transactionId (Optional) defaults to the last transaction
11620      */
11621     abort : function(transId){
11622         if(transId || this.isLoading()){
11623             Roo.lib.Ajax.abort(transId || this.transId);
11624         }
11625     },
11626
11627     // private
11628     handleResponse : function(response){
11629         this.transId = false;
11630         var options = response.argument.options;
11631         response.argument = options ? options.argument : null;
11632         this.fireEvent("requestcomplete", this, response, options);
11633         Roo.callback(options.success, options.scope, [response, options]);
11634         Roo.callback(options.callback, options.scope, [options, true, response]);
11635     },
11636
11637     // private
11638     handleFailure : function(response, e){
11639         this.transId = false;
11640         var options = response.argument.options;
11641         response.argument = options ? options.argument : null;
11642         this.fireEvent("requestexception", this, response, options, e);
11643         Roo.callback(options.failure, options.scope, [response, options]);
11644         Roo.callback(options.callback, options.scope, [options, false, response]);
11645     },
11646
11647     // private
11648     doFormUpload : function(o, ps, url){
11649         var id = Roo.id();
11650         var frame = document.createElement('iframe');
11651         frame.id = id;
11652         frame.name = id;
11653         frame.className = 'x-hidden';
11654         if(Roo.isIE){
11655             frame.src = Roo.SSL_SECURE_URL;
11656         }
11657         document.body.appendChild(frame);
11658
11659         if(Roo.isIE){
11660            document.frames[id].name = id;
11661         }
11662
11663         var form = Roo.getDom(o.form);
11664         form.target = id;
11665         form.method = 'POST';
11666         form.enctype = form.encoding = 'multipart/form-data';
11667         if(url){
11668             form.action = url;
11669         }
11670
11671         var hiddens, hd;
11672         if(ps){ // add dynamic params
11673             hiddens = [];
11674             ps = Roo.urlDecode(ps, false);
11675             for(var k in ps){
11676                 if(ps.hasOwnProperty(k)){
11677                     hd = document.createElement('input');
11678                     hd.type = 'hidden';
11679                     hd.name = k;
11680                     hd.value = ps[k];
11681                     form.appendChild(hd);
11682                     hiddens.push(hd);
11683                 }
11684             }
11685         }
11686
11687         function cb(){
11688             var r = {  // bogus response object
11689                 responseText : '',
11690                 responseXML : null
11691             };
11692
11693             r.argument = o ? o.argument : null;
11694
11695             try { //
11696                 var doc;
11697                 if(Roo.isIE){
11698                     doc = frame.contentWindow.document;
11699                 }else {
11700                     doc = (frame.contentDocument || window.frames[id].document);
11701                 }
11702                 if(doc && doc.body){
11703                     r.responseText = doc.body.innerHTML;
11704                 }
11705                 if(doc && doc.XMLDocument){
11706                     r.responseXML = doc.XMLDocument;
11707                 }else {
11708                     r.responseXML = doc;
11709                 }
11710             }
11711             catch(e) {
11712                 // ignore
11713             }
11714
11715             Roo.EventManager.removeListener(frame, 'load', cb, this);
11716
11717             this.fireEvent("requestcomplete", this, r, o);
11718             Roo.callback(o.success, o.scope, [r, o]);
11719             Roo.callback(o.callback, o.scope, [o, true, r]);
11720
11721             setTimeout(function(){document.body.removeChild(frame);}, 100);
11722         }
11723
11724         Roo.EventManager.on(frame, 'load', cb, this);
11725         form.submit();
11726
11727         if(hiddens){ // remove dynamic params
11728             for(var i = 0, len = hiddens.length; i < len; i++){
11729                 form.removeChild(hiddens[i]);
11730             }
11731         }
11732     }
11733 });
11734 /*
11735  * Based on:
11736  * Ext JS Library 1.1.1
11737  * Copyright(c) 2006-2007, Ext JS, LLC.
11738  *
11739  * Originally Released Under LGPL - original licence link has changed is not relivant.
11740  *
11741  * Fork - LGPL
11742  * <script type="text/javascript">
11743  */
11744  
11745 /**
11746  * Global Ajax request class.
11747  * 
11748  * @class Roo.Ajax
11749  * @extends Roo.data.Connection
11750  * @static
11751  * 
11752  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11753  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11754  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11755  * @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)
11756  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11757  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11758  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11759  */
11760 Roo.Ajax = new Roo.data.Connection({
11761     // fix up the docs
11762     /**
11763      * @scope Roo.Ajax
11764      * @type {Boolear} 
11765      */
11766     autoAbort : false,
11767
11768     /**
11769      * Serialize the passed form into a url encoded string
11770      * @scope Roo.Ajax
11771      * @param {String/HTMLElement} form
11772      * @return {String}
11773      */
11774     serializeForm : function(form){
11775         return Roo.lib.Ajax.serializeForm(form);
11776     }
11777 });/*
11778  * Based on:
11779  * Ext JS Library 1.1.1
11780  * Copyright(c) 2006-2007, Ext JS, LLC.
11781  *
11782  * Originally Released Under LGPL - original licence link has changed is not relivant.
11783  *
11784  * Fork - LGPL
11785  * <script type="text/javascript">
11786  */
11787
11788  
11789 /**
11790  * @class Roo.UpdateManager
11791  * @extends Roo.util.Observable
11792  * Provides AJAX-style update for Element object.<br><br>
11793  * Usage:<br>
11794  * <pre><code>
11795  * // Get it from a Roo.Element object
11796  * var el = Roo.get("foo");
11797  * var mgr = el.getUpdateManager();
11798  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11799  * ...
11800  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11801  * <br>
11802  * // or directly (returns the same UpdateManager instance)
11803  * var mgr = new Roo.UpdateManager("myElementId");
11804  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11805  * mgr.on("update", myFcnNeedsToKnow);
11806  * <br>
11807    // short handed call directly from the element object
11808    Roo.get("foo").load({
11809         url: "bar.php",
11810         scripts:true,
11811         params: "for=bar",
11812         text: "Loading Foo..."
11813    });
11814  * </code></pre>
11815  * @constructor
11816  * Create new UpdateManager directly.
11817  * @param {String/HTMLElement/Roo.Element} el The element to update
11818  * @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).
11819  */
11820 Roo.UpdateManager = function(el, forceNew){
11821     el = Roo.get(el);
11822     if(!forceNew && el.updateManager){
11823         return el.updateManager;
11824     }
11825     /**
11826      * The Element object
11827      * @type Roo.Element
11828      */
11829     this.el = el;
11830     /**
11831      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11832      * @type String
11833      */
11834     this.defaultUrl = null;
11835
11836     this.addEvents({
11837         /**
11838          * @event beforeupdate
11839          * Fired before an update is made, return false from your handler and the update is cancelled.
11840          * @param {Roo.Element} el
11841          * @param {String/Object/Function} url
11842          * @param {String/Object} params
11843          */
11844         "beforeupdate": true,
11845         /**
11846          * @event update
11847          * Fired after successful update is made.
11848          * @param {Roo.Element} el
11849          * @param {Object} oResponseObject The response Object
11850          */
11851         "update": true,
11852         /**
11853          * @event failure
11854          * Fired on update failure.
11855          * @param {Roo.Element} el
11856          * @param {Object} oResponseObject The response Object
11857          */
11858         "failure": true
11859     });
11860     var d = Roo.UpdateManager.defaults;
11861     /**
11862      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11863      * @type String
11864      */
11865     this.sslBlankUrl = d.sslBlankUrl;
11866     /**
11867      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11868      * @type Boolean
11869      */
11870     this.disableCaching = d.disableCaching;
11871     /**
11872      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11873      * @type String
11874      */
11875     this.indicatorText = d.indicatorText;
11876     /**
11877      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11878      * @type String
11879      */
11880     this.showLoadIndicator = d.showLoadIndicator;
11881     /**
11882      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11883      * @type Number
11884      */
11885     this.timeout = d.timeout;
11886
11887     /**
11888      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11889      * @type Boolean
11890      */
11891     this.loadScripts = d.loadScripts;
11892
11893     /**
11894      * Transaction object of current executing transaction
11895      */
11896     this.transaction = null;
11897
11898     /**
11899      * @private
11900      */
11901     this.autoRefreshProcId = null;
11902     /**
11903      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11904      * @type Function
11905      */
11906     this.refreshDelegate = this.refresh.createDelegate(this);
11907     /**
11908      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11909      * @type Function
11910      */
11911     this.updateDelegate = this.update.createDelegate(this);
11912     /**
11913      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11914      * @type Function
11915      */
11916     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11917     /**
11918      * @private
11919      */
11920     this.successDelegate = this.processSuccess.createDelegate(this);
11921     /**
11922      * @private
11923      */
11924     this.failureDelegate = this.processFailure.createDelegate(this);
11925
11926     if(!this.renderer){
11927      /**
11928       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11929       */
11930     this.renderer = new Roo.UpdateManager.BasicRenderer();
11931     }
11932     
11933     Roo.UpdateManager.superclass.constructor.call(this);
11934 };
11935
11936 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11937     /**
11938      * Get the Element this UpdateManager is bound to
11939      * @return {Roo.Element} The element
11940      */
11941     getEl : function(){
11942         return this.el;
11943     },
11944     /**
11945      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11946      * @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:
11947 <pre><code>
11948 um.update({<br/>
11949     url: "your-url.php",<br/>
11950     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11951     callback: yourFunction,<br/>
11952     scope: yourObject, //(optional scope)  <br/>
11953     discardUrl: false, <br/>
11954     nocache: false,<br/>
11955     text: "Loading...",<br/>
11956     timeout: 30,<br/>
11957     scripts: false<br/>
11958 });
11959 </code></pre>
11960      * The only required property is url. The optional properties nocache, text and scripts
11961      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11962      * @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}
11963      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11964      * @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.
11965      */
11966     update : function(url, params, callback, discardUrl){
11967         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11968             var method = this.method,
11969                 cfg;
11970             if(typeof url == "object"){ // must be config object
11971                 cfg = url;
11972                 url = cfg.url;
11973                 params = params || cfg.params;
11974                 callback = callback || cfg.callback;
11975                 discardUrl = discardUrl || cfg.discardUrl;
11976                 if(callback && cfg.scope){
11977                     callback = callback.createDelegate(cfg.scope);
11978                 }
11979                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11980                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11981                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11982                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11983                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11984             }
11985             this.showLoading();
11986             if(!discardUrl){
11987                 this.defaultUrl = url;
11988             }
11989             if(typeof url == "function"){
11990                 url = url.call(this);
11991             }
11992
11993             method = method || (params ? "POST" : "GET");
11994             if(method == "GET"){
11995                 url = this.prepareUrl(url);
11996             }
11997
11998             var o = Roo.apply(cfg ||{}, {
11999                 url : url,
12000                 params: params,
12001                 success: this.successDelegate,
12002                 failure: this.failureDelegate,
12003                 callback: undefined,
12004                 timeout: (this.timeout*1000),
12005                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12006             });
12007             Roo.log("updated manager called with timeout of " + o.timeout);
12008             this.transaction = Roo.Ajax.request(o);
12009         }
12010     },
12011
12012     /**
12013      * 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.
12014      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12015      * @param {String/HTMLElement} form The form Id or form element
12016      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12017      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12018      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12019      */
12020     formUpdate : function(form, url, reset, callback){
12021         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12022             if(typeof url == "function"){
12023                 url = url.call(this);
12024             }
12025             form = Roo.getDom(form);
12026             this.transaction = Roo.Ajax.request({
12027                 form: form,
12028                 url:url,
12029                 success: this.successDelegate,
12030                 failure: this.failureDelegate,
12031                 timeout: (this.timeout*1000),
12032                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12033             });
12034             this.showLoading.defer(1, this);
12035         }
12036     },
12037
12038     /**
12039      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12040      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12041      */
12042     refresh : function(callback){
12043         if(this.defaultUrl == null){
12044             return;
12045         }
12046         this.update(this.defaultUrl, null, callback, true);
12047     },
12048
12049     /**
12050      * Set this element to auto refresh.
12051      * @param {Number} interval How often to update (in seconds).
12052      * @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)
12053      * @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}
12054      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12055      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12056      */
12057     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12058         if(refreshNow){
12059             this.update(url || this.defaultUrl, params, callback, true);
12060         }
12061         if(this.autoRefreshProcId){
12062             clearInterval(this.autoRefreshProcId);
12063         }
12064         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12065     },
12066
12067     /**
12068      * Stop auto refresh on this element.
12069      */
12070      stopAutoRefresh : function(){
12071         if(this.autoRefreshProcId){
12072             clearInterval(this.autoRefreshProcId);
12073             delete this.autoRefreshProcId;
12074         }
12075     },
12076
12077     isAutoRefreshing : function(){
12078        return this.autoRefreshProcId ? true : false;
12079     },
12080     /**
12081      * Called to update the element to "Loading" state. Override to perform custom action.
12082      */
12083     showLoading : function(){
12084         if(this.showLoadIndicator){
12085             this.el.update(this.indicatorText);
12086         }
12087     },
12088
12089     /**
12090      * Adds unique parameter to query string if disableCaching = true
12091      * @private
12092      */
12093     prepareUrl : function(url){
12094         if(this.disableCaching){
12095             var append = "_dc=" + (new Date().getTime());
12096             if(url.indexOf("?") !== -1){
12097                 url += "&" + append;
12098             }else{
12099                 url += "?" + append;
12100             }
12101         }
12102         return url;
12103     },
12104
12105     /**
12106      * @private
12107      */
12108     processSuccess : function(response){
12109         this.transaction = null;
12110         if(response.argument.form && response.argument.reset){
12111             try{ // put in try/catch since some older FF releases had problems with this
12112                 response.argument.form.reset();
12113             }catch(e){}
12114         }
12115         if(this.loadScripts){
12116             this.renderer.render(this.el, response, this,
12117                 this.updateComplete.createDelegate(this, [response]));
12118         }else{
12119             this.renderer.render(this.el, response, this);
12120             this.updateComplete(response);
12121         }
12122     },
12123
12124     updateComplete : function(response){
12125         this.fireEvent("update", this.el, response);
12126         if(typeof response.argument.callback == "function"){
12127             response.argument.callback(this.el, true, response);
12128         }
12129     },
12130
12131     /**
12132      * @private
12133      */
12134     processFailure : function(response){
12135         this.transaction = null;
12136         this.fireEvent("failure", this.el, response);
12137         if(typeof response.argument.callback == "function"){
12138             response.argument.callback(this.el, false, response);
12139         }
12140     },
12141
12142     /**
12143      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12144      * @param {Object} renderer The object implementing the render() method
12145      */
12146     setRenderer : function(renderer){
12147         this.renderer = renderer;
12148     },
12149
12150     getRenderer : function(){
12151        return this.renderer;
12152     },
12153
12154     /**
12155      * Set the defaultUrl used for updates
12156      * @param {String/Function} defaultUrl The url or a function to call to get the url
12157      */
12158     setDefaultUrl : function(defaultUrl){
12159         this.defaultUrl = defaultUrl;
12160     },
12161
12162     /**
12163      * Aborts the executing transaction
12164      */
12165     abort : function(){
12166         if(this.transaction){
12167             Roo.Ajax.abort(this.transaction);
12168         }
12169     },
12170
12171     /**
12172      * Returns true if an update is in progress
12173      * @return {Boolean}
12174      */
12175     isUpdating : function(){
12176         if(this.transaction){
12177             return Roo.Ajax.isLoading(this.transaction);
12178         }
12179         return false;
12180     }
12181 });
12182
12183 /**
12184  * @class Roo.UpdateManager.defaults
12185  * @static (not really - but it helps the doc tool)
12186  * The defaults collection enables customizing the default properties of UpdateManager
12187  */
12188    Roo.UpdateManager.defaults = {
12189        /**
12190          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12191          * @type Number
12192          */
12193          timeout : 30,
12194
12195          /**
12196          * True to process scripts by default (Defaults to false).
12197          * @type Boolean
12198          */
12199         loadScripts : false,
12200
12201         /**
12202         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12203         * @type String
12204         */
12205         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12206         /**
12207          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12208          * @type Boolean
12209          */
12210         disableCaching : false,
12211         /**
12212          * Whether to show indicatorText when loading (Defaults to true).
12213          * @type Boolean
12214          */
12215         showLoadIndicator : true,
12216         /**
12217          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12218          * @type String
12219          */
12220         indicatorText : '<div class="loading-indicator">Loading...</div>'
12221    };
12222
12223 /**
12224  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12225  *Usage:
12226  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12227  * @param {String/HTMLElement/Roo.Element} el The element to update
12228  * @param {String} url The url
12229  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12230  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12231  * @static
12232  * @deprecated
12233  * @member Roo.UpdateManager
12234  */
12235 Roo.UpdateManager.updateElement = function(el, url, params, options){
12236     var um = Roo.get(el, true).getUpdateManager();
12237     Roo.apply(um, options);
12238     um.update(url, params, options ? options.callback : null);
12239 };
12240 // alias for backwards compat
12241 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12242 /**
12243  * @class Roo.UpdateManager.BasicRenderer
12244  * Default Content renderer. Updates the elements innerHTML with the responseText.
12245  */
12246 Roo.UpdateManager.BasicRenderer = function(){};
12247
12248 Roo.UpdateManager.BasicRenderer.prototype = {
12249     /**
12250      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12251      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12252      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12253      * @param {Roo.Element} el The element being rendered
12254      * @param {Object} response The YUI Connect response object
12255      * @param {UpdateManager} updateManager The calling update manager
12256      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12257      */
12258      render : function(el, response, updateManager, callback){
12259         el.update(response.responseText, updateManager.loadScripts, callback);
12260     }
12261 };
12262 /*
12263  * Based on:
12264  * Roo JS
12265  * (c)) Alan Knowles
12266  * Licence : LGPL
12267  */
12268
12269
12270 /**
12271  * @class Roo.DomTemplate
12272  * @extends Roo.Template
12273  * An effort at a dom based template engine..
12274  *
12275  * Similar to XTemplate, except it uses dom parsing to create the template..
12276  *
12277  * Supported features:
12278  *
12279  *  Tags:
12280
12281 <pre><code>
12282       {a_variable} - output encoded.
12283       {a_variable.format:("Y-m-d")} - call a method on the variable
12284       {a_variable:raw} - unencoded output
12285       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12286       {a_variable:this.method_on_template(...)} - call a method on the template object.
12287  
12288 </code></pre>
12289  *  The tpl tag:
12290 <pre><code>
12291         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12292         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12293         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12294         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12295   
12296 </code></pre>
12297  *      
12298  */
12299 Roo.DomTemplate = function()
12300 {
12301      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12302      if (this.html) {
12303         this.compile();
12304      }
12305 };
12306
12307
12308 Roo.extend(Roo.DomTemplate, Roo.Template, {
12309     /**
12310      * id counter for sub templates.
12311      */
12312     id : 0,
12313     /**
12314      * flag to indicate if dom parser is inside a pre,
12315      * it will strip whitespace if not.
12316      */
12317     inPre : false,
12318     
12319     /**
12320      * The various sub templates
12321      */
12322     tpls : false,
12323     
12324     
12325     
12326     /**
12327      *
12328      * basic tag replacing syntax
12329      * WORD:WORD()
12330      *
12331      * // you can fake an object call by doing this
12332      *  x.t:(test,tesT) 
12333      * 
12334      */
12335     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12336     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12337     
12338     iterChild : function (node, method) {
12339         
12340         var oldPre = this.inPre;
12341         if (node.tagName == 'PRE') {
12342             this.inPre = true;
12343         }
12344         for( var i = 0; i < node.childNodes.length; i++) {
12345             method.call(this, node.childNodes[i]);
12346         }
12347         this.inPre = oldPre;
12348     },
12349     
12350     
12351     
12352     /**
12353      * compile the template
12354      *
12355      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12356      *
12357      */
12358     compile: function()
12359     {
12360         var s = this.html;
12361         
12362         // covert the html into DOM...
12363         var doc = false;
12364         var div =false;
12365         try {
12366             doc = document.implementation.createHTMLDocument("");
12367             doc.documentElement.innerHTML =   this.html  ;
12368             div = doc.documentElement;
12369         } catch (e) {
12370             // old IE... - nasty -- it causes all sorts of issues.. with
12371             // images getting pulled from server..
12372             div = document.createElement('div');
12373             div.innerHTML = this.html;
12374         }
12375         //doc.documentElement.innerHTML = htmlBody
12376          
12377         
12378         
12379         this.tpls = [];
12380         var _t = this;
12381         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12382         
12383         var tpls = this.tpls;
12384         
12385         // create a top level template from the snippet..
12386         
12387         //Roo.log(div.innerHTML);
12388         
12389         var tpl = {
12390             uid : 'master',
12391             id : this.id++,
12392             attr : false,
12393             value : false,
12394             body : div.innerHTML,
12395             
12396             forCall : false,
12397             execCall : false,
12398             dom : div,
12399             isTop : true
12400             
12401         };
12402         tpls.unshift(tpl);
12403         
12404         
12405         // compile them...
12406         this.tpls = [];
12407         Roo.each(tpls, function(tp){
12408             this.compileTpl(tp);
12409             this.tpls[tp.id] = tp;
12410         }, this);
12411         
12412         this.master = tpls[0];
12413         return this;
12414         
12415         
12416     },
12417     
12418     compileNode : function(node, istop) {
12419         // test for
12420         //Roo.log(node);
12421         
12422         
12423         // skip anything not a tag..
12424         if (node.nodeType != 1) {
12425             if (node.nodeType == 3 && !this.inPre) {
12426                 // reduce white space..
12427                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12428                 
12429             }
12430             return;
12431         }
12432         
12433         var tpl = {
12434             uid : false,
12435             id : false,
12436             attr : false,
12437             value : false,
12438             body : '',
12439             
12440             forCall : false,
12441             execCall : false,
12442             dom : false,
12443             isTop : istop
12444             
12445             
12446         };
12447         
12448         
12449         switch(true) {
12450             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12451             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12452             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12453             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12454             // no default..
12455         }
12456         
12457         
12458         if (!tpl.attr) {
12459             // just itterate children..
12460             this.iterChild(node,this.compileNode);
12461             return;
12462         }
12463         tpl.uid = this.id++;
12464         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12465         node.removeAttribute('roo-'+ tpl.attr);
12466         if (tpl.attr != 'name') {
12467             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12468             node.parentNode.replaceChild(placeholder,  node);
12469         } else {
12470             
12471             var placeholder =  document.createElement('span');
12472             placeholder.className = 'roo-tpl-' + tpl.value;
12473             node.parentNode.replaceChild(placeholder,  node);
12474         }
12475         
12476         // parent now sees '{domtplXXXX}
12477         this.iterChild(node,this.compileNode);
12478         
12479         // we should now have node body...
12480         var div = document.createElement('div');
12481         div.appendChild(node);
12482         tpl.dom = node;
12483         // this has the unfortunate side effect of converting tagged attributes
12484         // eg. href="{...}" into %7C...%7D
12485         // this has been fixed by searching for those combo's although it's a bit hacky..
12486         
12487         
12488         tpl.body = div.innerHTML;
12489         
12490         
12491          
12492         tpl.id = tpl.uid;
12493         switch(tpl.attr) {
12494             case 'for' :
12495                 switch (tpl.value) {
12496                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12497                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12498                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12499                 }
12500                 break;
12501             
12502             case 'exec':
12503                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12504                 break;
12505             
12506             case 'if':     
12507                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12508                 break;
12509             
12510             case 'name':
12511                 tpl.id  = tpl.value; // replace non characters???
12512                 break;
12513             
12514         }
12515         
12516         
12517         this.tpls.push(tpl);
12518         
12519         
12520         
12521     },
12522     
12523     
12524     
12525     
12526     /**
12527      * Compile a segment of the template into a 'sub-template'
12528      *
12529      * 
12530      * 
12531      *
12532      */
12533     compileTpl : function(tpl)
12534     {
12535         var fm = Roo.util.Format;
12536         var useF = this.disableFormats !== true;
12537         
12538         var sep = Roo.isGecko ? "+\n" : ",\n";
12539         
12540         var undef = function(str) {
12541             Roo.debug && Roo.log("Property not found :"  + str);
12542             return '';
12543         };
12544           
12545         //Roo.log(tpl.body);
12546         
12547         
12548         
12549         var fn = function(m, lbrace, name, format, args)
12550         {
12551             //Roo.log("ARGS");
12552             //Roo.log(arguments);
12553             args = args ? args.replace(/\\'/g,"'") : args;
12554             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12555             if (typeof(format) == 'undefined') {
12556                 format =  'htmlEncode'; 
12557             }
12558             if (format == 'raw' ) {
12559                 format = false;
12560             }
12561             
12562             if(name.substr(0, 6) == 'domtpl'){
12563                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12564             }
12565             
12566             // build an array of options to determine if value is undefined..
12567             
12568             // basically get 'xxxx.yyyy' then do
12569             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12570             //    (function () { Roo.log("Property not found"); return ''; })() :
12571             //    ......
12572             
12573             var udef_ar = [];
12574             var lookfor = '';
12575             Roo.each(name.split('.'), function(st) {
12576                 lookfor += (lookfor.length ? '.': '') + st;
12577                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12578             });
12579             
12580             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12581             
12582             
12583             if(format && useF){
12584                 
12585                 args = args ? ',' + args : "";
12586                  
12587                 if(format.substr(0, 5) != "this."){
12588                     format = "fm." + format + '(';
12589                 }else{
12590                     format = 'this.call("'+ format.substr(5) + '", ';
12591                     args = ", values";
12592                 }
12593                 
12594                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12595             }
12596              
12597             if (args && args.length) {
12598                 // called with xxyx.yuu:(test,test)
12599                 // change to ()
12600                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12601             }
12602             // raw.. - :raw modifier..
12603             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12604             
12605         };
12606         var body;
12607         // branched to use + in gecko and [].join() in others
12608         if(Roo.isGecko){
12609             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12610                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12611                     "';};};";
12612         }else{
12613             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12614             body.push(tpl.body.replace(/(\r\n|\n)/g,
12615                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12616             body.push("'].join('');};};");
12617             body = body.join('');
12618         }
12619         
12620         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12621        
12622         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12623         eval(body);
12624         
12625         return this;
12626     },
12627      
12628     /**
12629      * same as applyTemplate, except it's done to one of the subTemplates
12630      * when using named templates, you can do:
12631      *
12632      * var str = pl.applySubTemplate('your-name', values);
12633      *
12634      * 
12635      * @param {Number} id of the template
12636      * @param {Object} values to apply to template
12637      * @param {Object} parent (normaly the instance of this object)
12638      */
12639     applySubTemplate : function(id, values, parent)
12640     {
12641         
12642         
12643         var t = this.tpls[id];
12644         
12645         
12646         try { 
12647             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12648                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12649                 return '';
12650             }
12651         } catch(e) {
12652             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12653             Roo.log(values);
12654           
12655             return '';
12656         }
12657         try { 
12658             
12659             if(t.execCall && t.execCall.call(this, values, parent)){
12660                 return '';
12661             }
12662         } catch(e) {
12663             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12664             Roo.log(values);
12665             return '';
12666         }
12667         
12668         try {
12669             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12670             parent = t.target ? values : parent;
12671             if(t.forCall && vs instanceof Array){
12672                 var buf = [];
12673                 for(var i = 0, len = vs.length; i < len; i++){
12674                     try {
12675                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12676                     } catch (e) {
12677                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12678                         Roo.log(e.body);
12679                         //Roo.log(t.compiled);
12680                         Roo.log(vs[i]);
12681                     }   
12682                 }
12683                 return buf.join('');
12684             }
12685         } catch (e) {
12686             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12687             Roo.log(values);
12688             return '';
12689         }
12690         try {
12691             return t.compiled.call(this, vs, 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(values);
12697             return '';
12698         }
12699     },
12700
12701    
12702
12703     applyTemplate : function(values){
12704         return this.master.compiled.call(this, values, {});
12705         //var s = this.subs;
12706     },
12707
12708     apply : function(){
12709         return this.applyTemplate.apply(this, arguments);
12710     }
12711
12712  });
12713
12714 Roo.DomTemplate.from = function(el){
12715     el = Roo.getDom(el);
12716     return new Roo.Domtemplate(el.value || el.innerHTML);
12717 };/*
12718  * Based on:
12719  * Ext JS Library 1.1.1
12720  * Copyright(c) 2006-2007, Ext JS, LLC.
12721  *
12722  * Originally Released Under LGPL - original licence link has changed is not relivant.
12723  *
12724  * Fork - LGPL
12725  * <script type="text/javascript">
12726  */
12727
12728 /**
12729  * @class Roo.util.DelayedTask
12730  * Provides a convenient method of performing setTimeout where a new
12731  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12732  * You can use this class to buffer
12733  * the keypress events for a certain number of milliseconds, and perform only if they stop
12734  * for that amount of time.
12735  * @constructor The parameters to this constructor serve as defaults and are not required.
12736  * @param {Function} fn (optional) The default function to timeout
12737  * @param {Object} scope (optional) The default scope of that timeout
12738  * @param {Array} args (optional) The default Array of arguments
12739  */
12740 Roo.util.DelayedTask = function(fn, scope, args){
12741     var id = null, d, t;
12742
12743     var call = function(){
12744         var now = new Date().getTime();
12745         if(now - t >= d){
12746             clearInterval(id);
12747             id = null;
12748             fn.apply(scope, args || []);
12749         }
12750     };
12751     /**
12752      * Cancels any pending timeout and queues a new one
12753      * @param {Number} delay The milliseconds to delay
12754      * @param {Function} newFn (optional) Overrides function passed to constructor
12755      * @param {Object} newScope (optional) Overrides scope passed to constructor
12756      * @param {Array} newArgs (optional) Overrides args passed to constructor
12757      */
12758     this.delay = function(delay, newFn, newScope, newArgs){
12759         if(id && delay != d){
12760             this.cancel();
12761         }
12762         d = delay;
12763         t = new Date().getTime();
12764         fn = newFn || fn;
12765         scope = newScope || scope;
12766         args = newArgs || args;
12767         if(!id){
12768             id = setInterval(call, d);
12769         }
12770     };
12771
12772     /**
12773      * Cancel the last queued timeout
12774      */
12775     this.cancel = function(){
12776         if(id){
12777             clearInterval(id);
12778             id = null;
12779         }
12780     };
12781 };/*
12782  * Based on:
12783  * Ext JS Library 1.1.1
12784  * Copyright(c) 2006-2007, Ext JS, LLC.
12785  *
12786  * Originally Released Under LGPL - original licence link has changed is not relivant.
12787  *
12788  * Fork - LGPL
12789  * <script type="text/javascript">
12790  */
12791  
12792  
12793 Roo.util.TaskRunner = function(interval){
12794     interval = interval || 10;
12795     var tasks = [], removeQueue = [];
12796     var id = 0;
12797     var running = false;
12798
12799     var stopThread = function(){
12800         running = false;
12801         clearInterval(id);
12802         id = 0;
12803     };
12804
12805     var startThread = function(){
12806         if(!running){
12807             running = true;
12808             id = setInterval(runTasks, interval);
12809         }
12810     };
12811
12812     var removeTask = function(task){
12813         removeQueue.push(task);
12814         if(task.onStop){
12815             task.onStop();
12816         }
12817     };
12818
12819     var runTasks = function(){
12820         if(removeQueue.length > 0){
12821             for(var i = 0, len = removeQueue.length; i < len; i++){
12822                 tasks.remove(removeQueue[i]);
12823             }
12824             removeQueue = [];
12825             if(tasks.length < 1){
12826                 stopThread();
12827                 return;
12828             }
12829         }
12830         var now = new Date().getTime();
12831         for(var i = 0, len = tasks.length; i < len; ++i){
12832             var t = tasks[i];
12833             var itime = now - t.taskRunTime;
12834             if(t.interval <= itime){
12835                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12836                 t.taskRunTime = now;
12837                 if(rt === false || t.taskRunCount === t.repeat){
12838                     removeTask(t);
12839                     return;
12840                 }
12841             }
12842             if(t.duration && t.duration <= (now - t.taskStartTime)){
12843                 removeTask(t);
12844             }
12845         }
12846     };
12847
12848     /**
12849      * Queues a new task.
12850      * @param {Object} task
12851      */
12852     this.start = function(task){
12853         tasks.push(task);
12854         task.taskStartTime = new Date().getTime();
12855         task.taskRunTime = 0;
12856         task.taskRunCount = 0;
12857         startThread();
12858         return task;
12859     };
12860
12861     this.stop = function(task){
12862         removeTask(task);
12863         return task;
12864     };
12865
12866     this.stopAll = function(){
12867         stopThread();
12868         for(var i = 0, len = tasks.length; i < len; i++){
12869             if(tasks[i].onStop){
12870                 tasks[i].onStop();
12871             }
12872         }
12873         tasks = [];
12874         removeQueue = [];
12875     };
12876 };
12877
12878 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12879  * Based on:
12880  * Ext JS Library 1.1.1
12881  * Copyright(c) 2006-2007, Ext JS, LLC.
12882  *
12883  * Originally Released Under LGPL - original licence link has changed is not relivant.
12884  *
12885  * Fork - LGPL
12886  * <script type="text/javascript">
12887  */
12888
12889  
12890 /**
12891  * @class Roo.util.MixedCollection
12892  * @extends Roo.util.Observable
12893  * A Collection class that maintains both numeric indexes and keys and exposes events.
12894  * @constructor
12895  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12896  * collection (defaults to false)
12897  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12898  * and return the key value for that item.  This is used when available to look up the key on items that
12899  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12900  * equivalent to providing an implementation for the {@link #getKey} method.
12901  */
12902 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12903     this.items = [];
12904     this.map = {};
12905     this.keys = [];
12906     this.length = 0;
12907     this.addEvents({
12908         /**
12909          * @event clear
12910          * Fires when the collection is cleared.
12911          */
12912         "clear" : true,
12913         /**
12914          * @event add
12915          * Fires when an item is added to the collection.
12916          * @param {Number} index The index at which the item was added.
12917          * @param {Object} o The item added.
12918          * @param {String} key The key associated with the added item.
12919          */
12920         "add" : true,
12921         /**
12922          * @event replace
12923          * Fires when an item is replaced in the collection.
12924          * @param {String} key he key associated with the new added.
12925          * @param {Object} old The item being replaced.
12926          * @param {Object} new The new item.
12927          */
12928         "replace" : true,
12929         /**
12930          * @event remove
12931          * Fires when an item is removed from the collection.
12932          * @param {Object} o The item being removed.
12933          * @param {String} key (optional) The key associated with the removed item.
12934          */
12935         "remove" : true,
12936         "sort" : true
12937     });
12938     this.allowFunctions = allowFunctions === true;
12939     if(keyFn){
12940         this.getKey = keyFn;
12941     }
12942     Roo.util.MixedCollection.superclass.constructor.call(this);
12943 };
12944
12945 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12946     allowFunctions : false,
12947     
12948 /**
12949  * Adds an item to the collection.
12950  * @param {String} key The key to associate with the item
12951  * @param {Object} o The item to add.
12952  * @return {Object} The item added.
12953  */
12954     add : function(key, o){
12955         if(arguments.length == 1){
12956             o = arguments[0];
12957             key = this.getKey(o);
12958         }
12959         if(typeof key == "undefined" || key === null){
12960             this.length++;
12961             this.items.push(o);
12962             this.keys.push(null);
12963         }else{
12964             var old = this.map[key];
12965             if(old){
12966                 return this.replace(key, o);
12967             }
12968             this.length++;
12969             this.items.push(o);
12970             this.map[key] = o;
12971             this.keys.push(key);
12972         }
12973         this.fireEvent("add", this.length-1, o, key);
12974         return o;
12975     },
12976        
12977 /**
12978   * MixedCollection has a generic way to fetch keys if you implement getKey.
12979 <pre><code>
12980 // normal way
12981 var mc = new Roo.util.MixedCollection();
12982 mc.add(someEl.dom.id, someEl);
12983 mc.add(otherEl.dom.id, otherEl);
12984 //and so on
12985
12986 // using getKey
12987 var mc = new Roo.util.MixedCollection();
12988 mc.getKey = function(el){
12989    return el.dom.id;
12990 };
12991 mc.add(someEl);
12992 mc.add(otherEl);
12993
12994 // or via the constructor
12995 var mc = new Roo.util.MixedCollection(false, function(el){
12996    return el.dom.id;
12997 });
12998 mc.add(someEl);
12999 mc.add(otherEl);
13000 </code></pre>
13001  * @param o {Object} The item for which to find the key.
13002  * @return {Object} The key for the passed item.
13003  */
13004     getKey : function(o){
13005          return o.id; 
13006     },
13007    
13008 /**
13009  * Replaces an item in the collection.
13010  * @param {String} key The key associated with the item to replace, or the item to replace.
13011  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13012  * @return {Object}  The new item.
13013  */
13014     replace : function(key, o){
13015         if(arguments.length == 1){
13016             o = arguments[0];
13017             key = this.getKey(o);
13018         }
13019         var old = this.item(key);
13020         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13021              return this.add(key, o);
13022         }
13023         var index = this.indexOfKey(key);
13024         this.items[index] = o;
13025         this.map[key] = o;
13026         this.fireEvent("replace", key, old, o);
13027         return o;
13028     },
13029    
13030 /**
13031  * Adds all elements of an Array or an Object to the collection.
13032  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13033  * an Array of values, each of which are added to the collection.
13034  */
13035     addAll : function(objs){
13036         if(arguments.length > 1 || objs instanceof Array){
13037             var args = arguments.length > 1 ? arguments : objs;
13038             for(var i = 0, len = args.length; i < len; i++){
13039                 this.add(args[i]);
13040             }
13041         }else{
13042             for(var key in objs){
13043                 if(this.allowFunctions || typeof objs[key] != "function"){
13044                     this.add(key, objs[key]);
13045                 }
13046             }
13047         }
13048     },
13049    
13050 /**
13051  * Executes the specified function once for every item in the collection, passing each
13052  * item as the first and only parameter. returning false from the function will stop the iteration.
13053  * @param {Function} fn The function to execute for each item.
13054  * @param {Object} scope (optional) The scope in which to execute the function.
13055  */
13056     each : function(fn, scope){
13057         var items = [].concat(this.items); // each safe for removal
13058         for(var i = 0, len = items.length; i < len; i++){
13059             if(fn.call(scope || items[i], items[i], i, len) === false){
13060                 break;
13061             }
13062         }
13063     },
13064    
13065 /**
13066  * Executes the specified function once for every key in the collection, passing each
13067  * key, and its associated item as the first two parameters.
13068  * @param {Function} fn The function to execute for each item.
13069  * @param {Object} scope (optional) The scope in which to execute the function.
13070  */
13071     eachKey : function(fn, scope){
13072         for(var i = 0, len = this.keys.length; i < len; i++){
13073             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13074         }
13075     },
13076    
13077 /**
13078  * Returns the first item in the collection which elicits a true return value from the
13079  * passed selection function.
13080  * @param {Function} fn The selection function to execute for each item.
13081  * @param {Object} scope (optional) The scope in which to execute the function.
13082  * @return {Object} The first item in the collection which returned true from the selection function.
13083  */
13084     find : function(fn, scope){
13085         for(var i = 0, len = this.items.length; i < len; i++){
13086             if(fn.call(scope || window, this.items[i], this.keys[i])){
13087                 return this.items[i];
13088             }
13089         }
13090         return null;
13091     },
13092    
13093 /**
13094  * Inserts an item at the specified index in the collection.
13095  * @param {Number} index The index to insert the item at.
13096  * @param {String} key The key to associate with the new item, or the item itself.
13097  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13098  * @return {Object} The item inserted.
13099  */
13100     insert : function(index, key, o){
13101         if(arguments.length == 2){
13102             o = arguments[1];
13103             key = this.getKey(o);
13104         }
13105         if(index >= this.length){
13106             return this.add(key, o);
13107         }
13108         this.length++;
13109         this.items.splice(index, 0, o);
13110         if(typeof key != "undefined" && key != null){
13111             this.map[key] = o;
13112         }
13113         this.keys.splice(index, 0, key);
13114         this.fireEvent("add", index, o, key);
13115         return o;
13116     },
13117    
13118 /**
13119  * Removed an item from the collection.
13120  * @param {Object} o The item to remove.
13121  * @return {Object} The item removed.
13122  */
13123     remove : function(o){
13124         return this.removeAt(this.indexOf(o));
13125     },
13126    
13127 /**
13128  * Remove an item from a specified index in the collection.
13129  * @param {Number} index The index within the collection of the item to remove.
13130  */
13131     removeAt : function(index){
13132         if(index < this.length && index >= 0){
13133             this.length--;
13134             var o = this.items[index];
13135             this.items.splice(index, 1);
13136             var key = this.keys[index];
13137             if(typeof key != "undefined"){
13138                 delete this.map[key];
13139             }
13140             this.keys.splice(index, 1);
13141             this.fireEvent("remove", o, key);
13142         }
13143     },
13144    
13145 /**
13146  * Removed an item associated with the passed key fom the collection.
13147  * @param {String} key The key of the item to remove.
13148  */
13149     removeKey : function(key){
13150         return this.removeAt(this.indexOfKey(key));
13151     },
13152    
13153 /**
13154  * Returns the number of items in the collection.
13155  * @return {Number} the number of items in the collection.
13156  */
13157     getCount : function(){
13158         return this.length; 
13159     },
13160    
13161 /**
13162  * Returns index within the collection of the passed Object.
13163  * @param {Object} o The item to find the index of.
13164  * @return {Number} index of the item.
13165  */
13166     indexOf : function(o){
13167         if(!this.items.indexOf){
13168             for(var i = 0, len = this.items.length; i < len; i++){
13169                 if(this.items[i] == o) {
13170                     return i;
13171                 }
13172             }
13173             return -1;
13174         }else{
13175             return this.items.indexOf(o);
13176         }
13177     },
13178    
13179 /**
13180  * Returns index within the collection of the passed key.
13181  * @param {String} key The key to find the index of.
13182  * @return {Number} index of the key.
13183  */
13184     indexOfKey : function(key){
13185         if(!this.keys.indexOf){
13186             for(var i = 0, len = this.keys.length; i < len; i++){
13187                 if(this.keys[i] == key) {
13188                     return i;
13189                 }
13190             }
13191             return -1;
13192         }else{
13193             return this.keys.indexOf(key);
13194         }
13195     },
13196    
13197 /**
13198  * Returns the item associated with the passed key OR index. Key has priority over index.
13199  * @param {String/Number} key The key or index of the item.
13200  * @return {Object} The item associated with the passed key.
13201  */
13202     item : function(key){
13203         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13204         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13205     },
13206     
13207 /**
13208  * Returns the item at the specified index.
13209  * @param {Number} index The index of the item.
13210  * @return {Object}
13211  */
13212     itemAt : function(index){
13213         return this.items[index];
13214     },
13215     
13216 /**
13217  * Returns the item associated with the passed key.
13218  * @param {String/Number} key The key of the item.
13219  * @return {Object} The item associated with the passed key.
13220  */
13221     key : function(key){
13222         return this.map[key];
13223     },
13224    
13225 /**
13226  * Returns true if the collection contains the passed Object as an item.
13227  * @param {Object} o  The Object to look for in the collection.
13228  * @return {Boolean} True if the collection contains the Object as an item.
13229  */
13230     contains : function(o){
13231         return this.indexOf(o) != -1;
13232     },
13233    
13234 /**
13235  * Returns true if the collection contains the passed Object as a key.
13236  * @param {String} key The key to look for in the collection.
13237  * @return {Boolean} True if the collection contains the Object as a key.
13238  */
13239     containsKey : function(key){
13240         return typeof this.map[key] != "undefined";
13241     },
13242    
13243 /**
13244  * Removes all items from the collection.
13245  */
13246     clear : function(){
13247         this.length = 0;
13248         this.items = [];
13249         this.keys = [];
13250         this.map = {};
13251         this.fireEvent("clear");
13252     },
13253    
13254 /**
13255  * Returns the first item in the collection.
13256  * @return {Object} the first item in the collection..
13257  */
13258     first : function(){
13259         return this.items[0]; 
13260     },
13261    
13262 /**
13263  * Returns the last item in the collection.
13264  * @return {Object} the last item in the collection..
13265  */
13266     last : function(){
13267         return this.items[this.length-1];   
13268     },
13269     
13270     _sort : function(property, dir, fn){
13271         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13272         fn = fn || function(a, b){
13273             return a-b;
13274         };
13275         var c = [], k = this.keys, items = this.items;
13276         for(var i = 0, len = items.length; i < len; i++){
13277             c[c.length] = {key: k[i], value: items[i], index: i};
13278         }
13279         c.sort(function(a, b){
13280             var v = fn(a[property], b[property]) * dsc;
13281             if(v == 0){
13282                 v = (a.index < b.index ? -1 : 1);
13283             }
13284             return v;
13285         });
13286         for(var i = 0, len = c.length; i < len; i++){
13287             items[i] = c[i].value;
13288             k[i] = c[i].key;
13289         }
13290         this.fireEvent("sort", this);
13291     },
13292     
13293     /**
13294      * Sorts this collection with the passed comparison function
13295      * @param {String} direction (optional) "ASC" or "DESC"
13296      * @param {Function} fn (optional) comparison function
13297      */
13298     sort : function(dir, fn){
13299         this._sort("value", dir, fn);
13300     },
13301     
13302     /**
13303      * Sorts this collection by keys
13304      * @param {String} direction (optional) "ASC" or "DESC"
13305      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13306      */
13307     keySort : function(dir, fn){
13308         this._sort("key", dir, fn || function(a, b){
13309             return String(a).toUpperCase()-String(b).toUpperCase();
13310         });
13311     },
13312     
13313     /**
13314      * Returns a range of items in this collection
13315      * @param {Number} startIndex (optional) defaults to 0
13316      * @param {Number} endIndex (optional) default to the last item
13317      * @return {Array} An array of items
13318      */
13319     getRange : function(start, end){
13320         var items = this.items;
13321         if(items.length < 1){
13322             return [];
13323         }
13324         start = start || 0;
13325         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13326         var r = [];
13327         if(start <= end){
13328             for(var i = start; i <= end; i++) {
13329                     r[r.length] = items[i];
13330             }
13331         }else{
13332             for(var i = start; i >= end; i--) {
13333                     r[r.length] = items[i];
13334             }
13335         }
13336         return r;
13337     },
13338         
13339     /**
13340      * Filter the <i>objects</i> in this collection by a specific property. 
13341      * Returns a new collection that has been filtered.
13342      * @param {String} property A property on your objects
13343      * @param {String/RegExp} value Either string that the property values 
13344      * should start with or a RegExp to test against the property
13345      * @return {MixedCollection} The new filtered collection
13346      */
13347     filter : function(property, value){
13348         if(!value.exec){ // not a regex
13349             value = String(value);
13350             if(value.length == 0){
13351                 return this.clone();
13352             }
13353             value = new RegExp("^" + Roo.escapeRe(value), "i");
13354         }
13355         return this.filterBy(function(o){
13356             return o && value.test(o[property]);
13357         });
13358         },
13359     
13360     /**
13361      * Filter by a function. * Returns a new collection that has been filtered.
13362      * The passed function will be called with each 
13363      * object in the collection. If the function returns true, the value is included 
13364      * otherwise it is filtered.
13365      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13366      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13367      * @return {MixedCollection} The new filtered collection
13368      */
13369     filterBy : function(fn, scope){
13370         var r = new Roo.util.MixedCollection();
13371         r.getKey = this.getKey;
13372         var k = this.keys, it = this.items;
13373         for(var i = 0, len = it.length; i < len; i++){
13374             if(fn.call(scope||this, it[i], k[i])){
13375                                 r.add(k[i], it[i]);
13376                         }
13377         }
13378         return r;
13379     },
13380     
13381     /**
13382      * Creates a duplicate of this collection
13383      * @return {MixedCollection}
13384      */
13385     clone : function(){
13386         var r = new Roo.util.MixedCollection();
13387         var k = this.keys, it = this.items;
13388         for(var i = 0, len = it.length; i < len; i++){
13389             r.add(k[i], it[i]);
13390         }
13391         r.getKey = this.getKey;
13392         return r;
13393     }
13394 });
13395 /**
13396  * Returns the item associated with the passed key or index.
13397  * @method
13398  * @param {String/Number} key The key or index of the item.
13399  * @return {Object} The item associated with the passed key.
13400  */
13401 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13402  * Based on:
13403  * Ext JS Library 1.1.1
13404  * Copyright(c) 2006-2007, Ext JS, LLC.
13405  *
13406  * Originally Released Under LGPL - original licence link has changed is not relivant.
13407  *
13408  * Fork - LGPL
13409  * <script type="text/javascript">
13410  */
13411 /**
13412  * @class Roo.util.JSON
13413  * Modified version of Douglas Crockford"s json.js that doesn"t
13414  * mess with the Object prototype 
13415  * http://www.json.org/js.html
13416  * @singleton
13417  */
13418 Roo.util.JSON = new (function(){
13419     var useHasOwn = {}.hasOwnProperty ? true : false;
13420     
13421     // crashes Safari in some instances
13422     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13423     
13424     var pad = function(n) {
13425         return n < 10 ? "0" + n : n;
13426     };
13427     
13428     var m = {
13429         "\b": '\\b',
13430         "\t": '\\t',
13431         "\n": '\\n',
13432         "\f": '\\f',
13433         "\r": '\\r',
13434         '"' : '\\"',
13435         "\\": '\\\\'
13436     };
13437
13438     var encodeString = function(s){
13439         if (/["\\\x00-\x1f]/.test(s)) {
13440             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13441                 var c = m[b];
13442                 if(c){
13443                     return c;
13444                 }
13445                 c = b.charCodeAt();
13446                 return "\\u00" +
13447                     Math.floor(c / 16).toString(16) +
13448                     (c % 16).toString(16);
13449             }) + '"';
13450         }
13451         return '"' + s + '"';
13452     };
13453     
13454     var encodeArray = function(o){
13455         var a = ["["], b, i, l = o.length, v;
13456             for (i = 0; i < l; i += 1) {
13457                 v = o[i];
13458                 switch (typeof v) {
13459                     case "undefined":
13460                     case "function":
13461                     case "unknown":
13462                         break;
13463                     default:
13464                         if (b) {
13465                             a.push(',');
13466                         }
13467                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13468                         b = true;
13469                 }
13470             }
13471             a.push("]");
13472             return a.join("");
13473     };
13474     
13475     var encodeDate = function(o){
13476         return '"' + o.getFullYear() + "-" +
13477                 pad(o.getMonth() + 1) + "-" +
13478                 pad(o.getDate()) + "T" +
13479                 pad(o.getHours()) + ":" +
13480                 pad(o.getMinutes()) + ":" +
13481                 pad(o.getSeconds()) + '"';
13482     };
13483     
13484     /**
13485      * Encodes an Object, Array or other value
13486      * @param {Mixed} o The variable to encode
13487      * @return {String} The JSON string
13488      */
13489     this.encode = function(o)
13490     {
13491         // should this be extended to fully wrap stringify..
13492         
13493         if(typeof o == "undefined" || o === null){
13494             return "null";
13495         }else if(o instanceof Array){
13496             return encodeArray(o);
13497         }else if(o instanceof Date){
13498             return encodeDate(o);
13499         }else if(typeof o == "string"){
13500             return encodeString(o);
13501         }else if(typeof o == "number"){
13502             return isFinite(o) ? String(o) : "null";
13503         }else if(typeof o == "boolean"){
13504             return String(o);
13505         }else {
13506             var a = ["{"], b, i, v;
13507             for (i in o) {
13508                 if(!useHasOwn || o.hasOwnProperty(i)) {
13509                     v = o[i];
13510                     switch (typeof v) {
13511                     case "undefined":
13512                     case "function":
13513                     case "unknown":
13514                         break;
13515                     default:
13516                         if(b){
13517                             a.push(',');
13518                         }
13519                         a.push(this.encode(i), ":",
13520                                 v === null ? "null" : this.encode(v));
13521                         b = true;
13522                     }
13523                 }
13524             }
13525             a.push("}");
13526             return a.join("");
13527         }
13528     };
13529     
13530     /**
13531      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13532      * @param {String} json The JSON string
13533      * @return {Object} The resulting object
13534      */
13535     this.decode = function(json){
13536         
13537         return  /** eval:var:json */ eval("(" + json + ')');
13538     };
13539 })();
13540 /** 
13541  * Shorthand for {@link Roo.util.JSON#encode}
13542  * @member Roo encode 
13543  * @method */
13544 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13545 /** 
13546  * Shorthand for {@link Roo.util.JSON#decode}
13547  * @member Roo decode 
13548  * @method */
13549 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13550 /*
13551  * Based on:
13552  * Ext JS Library 1.1.1
13553  * Copyright(c) 2006-2007, Ext JS, LLC.
13554  *
13555  * Originally Released Under LGPL - original licence link has changed is not relivant.
13556  *
13557  * Fork - LGPL
13558  * <script type="text/javascript">
13559  */
13560  
13561 /**
13562  * @class Roo.util.Format
13563  * Reusable data formatting functions
13564  * @singleton
13565  */
13566 Roo.util.Format = function(){
13567     var trimRe = /^\s+|\s+$/g;
13568     return {
13569         /**
13570          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13571          * @param {String} value The string to truncate
13572          * @param {Number} length The maximum length to allow before truncating
13573          * @return {String} The converted text
13574          */
13575         ellipsis : function(value, len){
13576             if(value && value.length > len){
13577                 return value.substr(0, len-3)+"...";
13578             }
13579             return value;
13580         },
13581
13582         /**
13583          * Checks a reference and converts it to empty string if it is undefined
13584          * @param {Mixed} value Reference to check
13585          * @return {Mixed} Empty string if converted, otherwise the original value
13586          */
13587         undef : function(value){
13588             return typeof value != "undefined" ? value : "";
13589         },
13590
13591         /**
13592          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13593          * @param {String} value The string to encode
13594          * @return {String} The encoded text
13595          */
13596         htmlEncode : function(value){
13597             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13598         },
13599
13600         /**
13601          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13602          * @param {String} value The string to decode
13603          * @return {String} The decoded text
13604          */
13605         htmlDecode : function(value){
13606             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13607         },
13608
13609         /**
13610          * Trims any whitespace from either side of a string
13611          * @param {String} value The text to trim
13612          * @return {String} The trimmed text
13613          */
13614         trim : function(value){
13615             return String(value).replace(trimRe, "");
13616         },
13617
13618         /**
13619          * Returns a substring from within an original string
13620          * @param {String} value The original text
13621          * @param {Number} start The start index of the substring
13622          * @param {Number} length The length of the substring
13623          * @return {String} The substring
13624          */
13625         substr : function(value, start, length){
13626             return String(value).substr(start, length);
13627         },
13628
13629         /**
13630          * Converts a string to all lower case letters
13631          * @param {String} value The text to convert
13632          * @return {String} The converted text
13633          */
13634         lowercase : function(value){
13635             return String(value).toLowerCase();
13636         },
13637
13638         /**
13639          * Converts a string to all upper case letters
13640          * @param {String} value The text to convert
13641          * @return {String} The converted text
13642          */
13643         uppercase : function(value){
13644             return String(value).toUpperCase();
13645         },
13646
13647         /**
13648          * Converts the first character only of a string to upper case
13649          * @param {String} value The text to convert
13650          * @return {String} The converted text
13651          */
13652         capitalize : function(value){
13653             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13654         },
13655
13656         // private
13657         call : function(value, fn){
13658             if(arguments.length > 2){
13659                 var args = Array.prototype.slice.call(arguments, 2);
13660                 args.unshift(value);
13661                  
13662                 return /** eval:var:value */  eval(fn).apply(window, args);
13663             }else{
13664                 /** eval:var:value */
13665                 return /** eval:var:value */ eval(fn).call(window, value);
13666             }
13667         },
13668
13669        
13670         /**
13671          * safer version of Math.toFixed..??/
13672          * @param {Number/String} value The numeric value to format
13673          * @param {Number/String} value Decimal places 
13674          * @return {String} The formatted currency string
13675          */
13676         toFixed : function(v, n)
13677         {
13678             // why not use to fixed - precision is buggered???
13679             if (!n) {
13680                 return Math.round(v-0);
13681             }
13682             var fact = Math.pow(10,n+1);
13683             v = (Math.round((v-0)*fact))/fact;
13684             var z = (''+fact).substring(2);
13685             if (v == Math.floor(v)) {
13686                 return Math.floor(v) + '.' + z;
13687             }
13688             
13689             // now just padd decimals..
13690             var ps = String(v).split('.');
13691             var fd = (ps[1] + z);
13692             var r = fd.substring(0,n); 
13693             var rm = fd.substring(n); 
13694             if (rm < 5) {
13695                 return ps[0] + '.' + r;
13696             }
13697             r*=1; // turn it into a number;
13698             r++;
13699             if (String(r).length != n) {
13700                 ps[0]*=1;
13701                 ps[0]++;
13702                 r = String(r).substring(1); // chop the end off.
13703             }
13704             
13705             return ps[0] + '.' + r;
13706              
13707         },
13708         
13709         /**
13710          * Format a number as US currency
13711          * @param {Number/String} value The numeric value to format
13712          * @return {String} The formatted currency string
13713          */
13714         usMoney : function(v){
13715             return '$' + Roo.util.Format.number(v);
13716         },
13717         
13718         /**
13719          * Format a number
13720          * eventually this should probably emulate php's number_format
13721          * @param {Number/String} value The numeric value to format
13722          * @param {Number} decimals number of decimal places
13723          * @return {String} The formatted currency string
13724          */
13725         number : function(v,decimals)
13726         {
13727             // multiply and round.
13728             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13729             var mul = Math.pow(10, decimals);
13730             var zero = String(mul).substring(1);
13731             v = (Math.round((v-0)*mul))/mul;
13732             
13733             // if it's '0' number.. then
13734             
13735             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13736             v = String(v);
13737             var ps = v.split('.');
13738             var whole = ps[0];
13739             
13740             
13741             var r = /(\d+)(\d{3})/;
13742             // add comma's
13743             while (r.test(whole)) {
13744                 whole = whole.replace(r, '$1' + ',' + '$2');
13745             }
13746             
13747             
13748             var sub = ps[1] ?
13749                     // has decimals..
13750                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13751                     // does not have decimals
13752                     (decimals ? ('.' + zero) : '');
13753             
13754             
13755             return whole + sub ;
13756         },
13757         
13758         /**
13759          * Parse a value into a formatted date using the specified format pattern.
13760          * @param {Mixed} value The value to format
13761          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13762          * @return {String} The formatted date string
13763          */
13764         date : function(v, format){
13765             if(!v){
13766                 return "";
13767             }
13768             if(!(v instanceof Date)){
13769                 v = new Date(Date.parse(v));
13770             }
13771             return v.dateFormat(format || Roo.util.Format.defaults.date);
13772         },
13773
13774         /**
13775          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13776          * @param {String} format Any valid date format string
13777          * @return {Function} The date formatting function
13778          */
13779         dateRenderer : function(format){
13780             return function(v){
13781                 return Roo.util.Format.date(v, format);  
13782             };
13783         },
13784
13785         // private
13786         stripTagsRE : /<\/?[^>]+>/gi,
13787         
13788         /**
13789          * Strips all HTML tags
13790          * @param {Mixed} value The text from which to strip tags
13791          * @return {String} The stripped text
13792          */
13793         stripTags : function(v){
13794             return !v ? v : String(v).replace(this.stripTagsRE, "");
13795         }
13796     };
13797 }();
13798 Roo.util.Format.defaults = {
13799     date : 'd/M/Y'
13800 };/*
13801  * Based on:
13802  * Ext JS Library 1.1.1
13803  * Copyright(c) 2006-2007, Ext JS, LLC.
13804  *
13805  * Originally Released Under LGPL - original licence link has changed is not relivant.
13806  *
13807  * Fork - LGPL
13808  * <script type="text/javascript">
13809  */
13810
13811
13812  
13813
13814 /**
13815  * @class Roo.MasterTemplate
13816  * @extends Roo.Template
13817  * Provides a template that can have child templates. The syntax is:
13818 <pre><code>
13819 var t = new Roo.MasterTemplate(
13820         '&lt;select name="{name}"&gt;',
13821                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13822         '&lt;/select&gt;'
13823 );
13824 t.add('options', {value: 'foo', text: 'bar'});
13825 // or you can add multiple child elements in one shot
13826 t.addAll('options', [
13827     {value: 'foo', text: 'bar'},
13828     {value: 'foo2', text: 'bar2'},
13829     {value: 'foo3', text: 'bar3'}
13830 ]);
13831 // then append, applying the master template values
13832 t.append('my-form', {name: 'my-select'});
13833 </code></pre>
13834 * A name attribute for the child template is not required if you have only one child
13835 * template or you want to refer to them by index.
13836  */
13837 Roo.MasterTemplate = function(){
13838     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13839     this.originalHtml = this.html;
13840     var st = {};
13841     var m, re = this.subTemplateRe;
13842     re.lastIndex = 0;
13843     var subIndex = 0;
13844     while(m = re.exec(this.html)){
13845         var name = m[1], content = m[2];
13846         st[subIndex] = {
13847             name: name,
13848             index: subIndex,
13849             buffer: [],
13850             tpl : new Roo.Template(content)
13851         };
13852         if(name){
13853             st[name] = st[subIndex];
13854         }
13855         st[subIndex].tpl.compile();
13856         st[subIndex].tpl.call = this.call.createDelegate(this);
13857         subIndex++;
13858     }
13859     this.subCount = subIndex;
13860     this.subs = st;
13861 };
13862 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13863     /**
13864     * The regular expression used to match sub templates
13865     * @type RegExp
13866     * @property
13867     */
13868     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13869
13870     /**
13871      * Applies the passed values to a child template.
13872      * @param {String/Number} name (optional) The name or index of the child template
13873      * @param {Array/Object} values The values to be applied to the template
13874      * @return {MasterTemplate} this
13875      */
13876      add : function(name, values){
13877         if(arguments.length == 1){
13878             values = arguments[0];
13879             name = 0;
13880         }
13881         var s = this.subs[name];
13882         s.buffer[s.buffer.length] = s.tpl.apply(values);
13883         return this;
13884     },
13885
13886     /**
13887      * Applies all the passed values to a child template.
13888      * @param {String/Number} name (optional) The name or index of the child template
13889      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13890      * @param {Boolean} reset (optional) True to reset the template first
13891      * @return {MasterTemplate} this
13892      */
13893     fill : function(name, values, reset){
13894         var a = arguments;
13895         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13896             values = a[0];
13897             name = 0;
13898             reset = a[1];
13899         }
13900         if(reset){
13901             this.reset();
13902         }
13903         for(var i = 0, len = values.length; i < len; i++){
13904             this.add(name, values[i]);
13905         }
13906         return this;
13907     },
13908
13909     /**
13910      * Resets the template for reuse
13911      * @return {MasterTemplate} this
13912      */
13913      reset : function(){
13914         var s = this.subs;
13915         for(var i = 0; i < this.subCount; i++){
13916             s[i].buffer = [];
13917         }
13918         return this;
13919     },
13920
13921     applyTemplate : function(values){
13922         var s = this.subs;
13923         var replaceIndex = -1;
13924         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13925             return s[++replaceIndex].buffer.join("");
13926         });
13927         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13928     },
13929
13930     apply : function(){
13931         return this.applyTemplate.apply(this, arguments);
13932     },
13933
13934     compile : function(){return this;}
13935 });
13936
13937 /**
13938  * Alias for fill().
13939  * @method
13940  */
13941 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13942  /**
13943  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13944  * var tpl = Roo.MasterTemplate.from('element-id');
13945  * @param {String/HTMLElement} el
13946  * @param {Object} config
13947  * @static
13948  */
13949 Roo.MasterTemplate.from = function(el, config){
13950     el = Roo.getDom(el);
13951     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13952 };/*
13953  * Based on:
13954  * Ext JS Library 1.1.1
13955  * Copyright(c) 2006-2007, Ext JS, LLC.
13956  *
13957  * Originally Released Under LGPL - original licence link has changed is not relivant.
13958  *
13959  * Fork - LGPL
13960  * <script type="text/javascript">
13961  */
13962
13963  
13964 /**
13965  * @class Roo.util.CSS
13966  * Utility class for manipulating CSS rules
13967  * @singleton
13968  */
13969 Roo.util.CSS = function(){
13970         var rules = null;
13971         var doc = document;
13972
13973     var camelRe = /(-[a-z])/gi;
13974     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13975
13976    return {
13977    /**
13978     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13979     * tag and appended to the HEAD of the document.
13980     * @param {String|Object} cssText The text containing the css rules
13981     * @param {String} id An id to add to the stylesheet for later removal
13982     * @return {StyleSheet}
13983     */
13984     createStyleSheet : function(cssText, id){
13985         var ss;
13986         var head = doc.getElementsByTagName("head")[0];
13987         var nrules = doc.createElement("style");
13988         nrules.setAttribute("type", "text/css");
13989         if(id){
13990             nrules.setAttribute("id", id);
13991         }
13992         if (typeof(cssText) != 'string') {
13993             // support object maps..
13994             // not sure if this a good idea.. 
13995             // perhaps it should be merged with the general css handling
13996             // and handle js style props.
13997             var cssTextNew = [];
13998             for(var n in cssText) {
13999                 var citems = [];
14000                 for(var k in cssText[n]) {
14001                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14002                 }
14003                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14004                 
14005             }
14006             cssText = cssTextNew.join("\n");
14007             
14008         }
14009        
14010        
14011        if(Roo.isIE){
14012            head.appendChild(nrules);
14013            ss = nrules.styleSheet;
14014            ss.cssText = cssText;
14015        }else{
14016            try{
14017                 nrules.appendChild(doc.createTextNode(cssText));
14018            }catch(e){
14019                nrules.cssText = cssText; 
14020            }
14021            head.appendChild(nrules);
14022            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14023        }
14024        this.cacheStyleSheet(ss);
14025        return ss;
14026    },
14027
14028    /**
14029     * Removes a style or link tag by id
14030     * @param {String} id The id of the tag
14031     */
14032    removeStyleSheet : function(id){
14033        var existing = doc.getElementById(id);
14034        if(existing){
14035            existing.parentNode.removeChild(existing);
14036        }
14037    },
14038
14039    /**
14040     * Dynamically swaps an existing stylesheet reference for a new one
14041     * @param {String} id The id of an existing link tag to remove
14042     * @param {String} url The href of the new stylesheet to include
14043     */
14044    swapStyleSheet : function(id, url){
14045        this.removeStyleSheet(id);
14046        var ss = doc.createElement("link");
14047        ss.setAttribute("rel", "stylesheet");
14048        ss.setAttribute("type", "text/css");
14049        ss.setAttribute("id", id);
14050        ss.setAttribute("href", url);
14051        doc.getElementsByTagName("head")[0].appendChild(ss);
14052    },
14053    
14054    /**
14055     * Refresh the rule cache if you have dynamically added stylesheets
14056     * @return {Object} An object (hash) of rules indexed by selector
14057     */
14058    refreshCache : function(){
14059        return this.getRules(true);
14060    },
14061
14062    // private
14063    cacheStyleSheet : function(stylesheet){
14064        if(!rules){
14065            rules = {};
14066        }
14067        try{// try catch for cross domain access issue
14068            var ssRules = stylesheet.cssRules || stylesheet.rules;
14069            for(var j = ssRules.length-1; j >= 0; --j){
14070                rules[ssRules[j].selectorText] = ssRules[j];
14071            }
14072        }catch(e){}
14073    },
14074    
14075    /**
14076     * Gets all css rules for the document
14077     * @param {Boolean} refreshCache true to refresh the internal cache
14078     * @return {Object} An object (hash) of rules indexed by selector
14079     */
14080    getRules : function(refreshCache){
14081                 if(rules == null || refreshCache){
14082                         rules = {};
14083                         var ds = doc.styleSheets;
14084                         for(var i =0, len = ds.length; i < len; i++){
14085                             try{
14086                         this.cacheStyleSheet(ds[i]);
14087                     }catch(e){} 
14088                 }
14089                 }
14090                 return rules;
14091         },
14092         
14093         /**
14094     * Gets an an individual CSS rule by selector(s)
14095     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14096     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14097     * @return {CSSRule} The CSS rule or null if one is not found
14098     */
14099    getRule : function(selector, refreshCache){
14100                 var rs = this.getRules(refreshCache);
14101                 if(!(selector instanceof Array)){
14102                     return rs[selector];
14103                 }
14104                 for(var i = 0; i < selector.length; i++){
14105                         if(rs[selector[i]]){
14106                                 return rs[selector[i]];
14107                         }
14108                 }
14109                 return null;
14110         },
14111         
14112         
14113         /**
14114     * Updates a rule property
14115     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14116     * @param {String} property The css property
14117     * @param {String} value The new value for the property
14118     * @return {Boolean} true If a rule was found and updated
14119     */
14120    updateRule : function(selector, property, value){
14121                 if(!(selector instanceof Array)){
14122                         var rule = this.getRule(selector);
14123                         if(rule){
14124                                 rule.style[property.replace(camelRe, camelFn)] = value;
14125                                 return true;
14126                         }
14127                 }else{
14128                         for(var i = 0; i < selector.length; i++){
14129                                 if(this.updateRule(selector[i], property, value)){
14130                                         return true;
14131                                 }
14132                         }
14133                 }
14134                 return false;
14135         }
14136    };   
14137 }();/*
14138  * Based on:
14139  * Ext JS Library 1.1.1
14140  * Copyright(c) 2006-2007, Ext JS, LLC.
14141  *
14142  * Originally Released Under LGPL - original licence link has changed is not relivant.
14143  *
14144  * Fork - LGPL
14145  * <script type="text/javascript">
14146  */
14147
14148  
14149
14150 /**
14151  * @class Roo.util.ClickRepeater
14152  * @extends Roo.util.Observable
14153  * 
14154  * A wrapper class which can be applied to any element. Fires a "click" event while the
14155  * mouse is pressed. The interval between firings may be specified in the config but
14156  * defaults to 10 milliseconds.
14157  * 
14158  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14159  * 
14160  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14161  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14162  * Similar to an autorepeat key delay.
14163  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14164  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14165  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14166  *           "interval" and "delay" are ignored. "immediate" is honored.
14167  * @cfg {Boolean} preventDefault True to prevent the default click event
14168  * @cfg {Boolean} stopDefault True to stop the default click event
14169  * 
14170  * @history
14171  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14172  *     2007-02-02 jvs Renamed to ClickRepeater
14173  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14174  *
14175  *  @constructor
14176  * @param {String/HTMLElement/Element} el The element to listen on
14177  * @param {Object} config
14178  **/
14179 Roo.util.ClickRepeater = function(el, config)
14180 {
14181     this.el = Roo.get(el);
14182     this.el.unselectable();
14183
14184     Roo.apply(this, config);
14185
14186     this.addEvents({
14187     /**
14188      * @event mousedown
14189      * Fires when the mouse button is depressed.
14190      * @param {Roo.util.ClickRepeater} this
14191      */
14192         "mousedown" : true,
14193     /**
14194      * @event click
14195      * Fires on a specified interval during the time the element is pressed.
14196      * @param {Roo.util.ClickRepeater} this
14197      */
14198         "click" : true,
14199     /**
14200      * @event mouseup
14201      * Fires when the mouse key is released.
14202      * @param {Roo.util.ClickRepeater} this
14203      */
14204         "mouseup" : true
14205     });
14206
14207     this.el.on("mousedown", this.handleMouseDown, this);
14208     if(this.preventDefault || this.stopDefault){
14209         this.el.on("click", function(e){
14210             if(this.preventDefault){
14211                 e.preventDefault();
14212             }
14213             if(this.stopDefault){
14214                 e.stopEvent();
14215             }
14216         }, this);
14217     }
14218
14219     // allow inline handler
14220     if(this.handler){
14221         this.on("click", this.handler,  this.scope || this);
14222     }
14223
14224     Roo.util.ClickRepeater.superclass.constructor.call(this);
14225 };
14226
14227 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14228     interval : 20,
14229     delay: 250,
14230     preventDefault : true,
14231     stopDefault : false,
14232     timer : 0,
14233
14234     // private
14235     handleMouseDown : function(){
14236         clearTimeout(this.timer);
14237         this.el.blur();
14238         if(this.pressClass){
14239             this.el.addClass(this.pressClass);
14240         }
14241         this.mousedownTime = new Date();
14242
14243         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14244         this.el.on("mouseout", this.handleMouseOut, this);
14245
14246         this.fireEvent("mousedown", this);
14247         this.fireEvent("click", this);
14248         
14249         this.timer = this.click.defer(this.delay || this.interval, this);
14250     },
14251
14252     // private
14253     click : function(){
14254         this.fireEvent("click", this);
14255         this.timer = this.click.defer(this.getInterval(), this);
14256     },
14257
14258     // private
14259     getInterval: function(){
14260         if(!this.accelerate){
14261             return this.interval;
14262         }
14263         var pressTime = this.mousedownTime.getElapsed();
14264         if(pressTime < 500){
14265             return 400;
14266         }else if(pressTime < 1700){
14267             return 320;
14268         }else if(pressTime < 2600){
14269             return 250;
14270         }else if(pressTime < 3500){
14271             return 180;
14272         }else if(pressTime < 4400){
14273             return 140;
14274         }else if(pressTime < 5300){
14275             return 80;
14276         }else if(pressTime < 6200){
14277             return 50;
14278         }else{
14279             return 10;
14280         }
14281     },
14282
14283     // private
14284     handleMouseOut : function(){
14285         clearTimeout(this.timer);
14286         if(this.pressClass){
14287             this.el.removeClass(this.pressClass);
14288         }
14289         this.el.on("mouseover", this.handleMouseReturn, this);
14290     },
14291
14292     // private
14293     handleMouseReturn : function(){
14294         this.el.un("mouseover", this.handleMouseReturn);
14295         if(this.pressClass){
14296             this.el.addClass(this.pressClass);
14297         }
14298         this.click();
14299     },
14300
14301     // private
14302     handleMouseUp : function(){
14303         clearTimeout(this.timer);
14304         this.el.un("mouseover", this.handleMouseReturn);
14305         this.el.un("mouseout", this.handleMouseOut);
14306         Roo.get(document).un("mouseup", this.handleMouseUp);
14307         this.el.removeClass(this.pressClass);
14308         this.fireEvent("mouseup", this);
14309     }
14310 });/*
14311  * Based on:
14312  * Ext JS Library 1.1.1
14313  * Copyright(c) 2006-2007, Ext JS, LLC.
14314  *
14315  * Originally Released Under LGPL - original licence link has changed is not relivant.
14316  *
14317  * Fork - LGPL
14318  * <script type="text/javascript">
14319  */
14320
14321  
14322 /**
14323  * @class Roo.KeyNav
14324  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14325  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14326  * way to implement custom navigation schemes for any UI component.</p>
14327  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14328  * pageUp, pageDown, del, home, end.  Usage:</p>
14329  <pre><code>
14330 var nav = new Roo.KeyNav("my-element", {
14331     "left" : function(e){
14332         this.moveLeft(e.ctrlKey);
14333     },
14334     "right" : function(e){
14335         this.moveRight(e.ctrlKey);
14336     },
14337     "enter" : function(e){
14338         this.save();
14339     },
14340     scope : this
14341 });
14342 </code></pre>
14343  * @constructor
14344  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14345  * @param {Object} config The config
14346  */
14347 Roo.KeyNav = function(el, config){
14348     this.el = Roo.get(el);
14349     Roo.apply(this, config);
14350     if(!this.disabled){
14351         this.disabled = true;
14352         this.enable();
14353     }
14354 };
14355
14356 Roo.KeyNav.prototype = {
14357     /**
14358      * @cfg {Boolean} disabled
14359      * True to disable this KeyNav instance (defaults to false)
14360      */
14361     disabled : false,
14362     /**
14363      * @cfg {String} defaultEventAction
14364      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14365      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14366      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14367      */
14368     defaultEventAction: "stopEvent",
14369     /**
14370      * @cfg {Boolean} forceKeyDown
14371      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14372      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14373      * handle keydown instead of keypress.
14374      */
14375     forceKeyDown : false,
14376
14377     // private
14378     prepareEvent : function(e){
14379         var k = e.getKey();
14380         var h = this.keyToHandler[k];
14381         //if(h && this[h]){
14382         //    e.stopPropagation();
14383         //}
14384         if(Roo.isSafari && h && k >= 37 && k <= 40){
14385             e.stopEvent();
14386         }
14387     },
14388
14389     // private
14390     relay : function(e){
14391         var k = e.getKey();
14392         var h = this.keyToHandler[k];
14393         if(h && this[h]){
14394             if(this.doRelay(e, this[h], h) !== true){
14395                 e[this.defaultEventAction]();
14396             }
14397         }
14398     },
14399
14400     // private
14401     doRelay : function(e, h, hname){
14402         return h.call(this.scope || this, e);
14403     },
14404
14405     // possible handlers
14406     enter : false,
14407     left : false,
14408     right : false,
14409     up : false,
14410     down : false,
14411     tab : false,
14412     esc : false,
14413     pageUp : false,
14414     pageDown : false,
14415     del : false,
14416     home : false,
14417     end : false,
14418
14419     // quick lookup hash
14420     keyToHandler : {
14421         37 : "left",
14422         39 : "right",
14423         38 : "up",
14424         40 : "down",
14425         33 : "pageUp",
14426         34 : "pageDown",
14427         46 : "del",
14428         36 : "home",
14429         35 : "end",
14430         13 : "enter",
14431         27 : "esc",
14432         9  : "tab"
14433     },
14434
14435         /**
14436          * Enable this KeyNav
14437          */
14438         enable: function(){
14439                 if(this.disabled){
14440             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14441             // the EventObject will normalize Safari automatically
14442             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14443                 this.el.on("keydown", this.relay,  this);
14444             }else{
14445                 this.el.on("keydown", this.prepareEvent,  this);
14446                 this.el.on("keypress", this.relay,  this);
14447             }
14448                     this.disabled = false;
14449                 }
14450         },
14451
14452         /**
14453          * Disable this KeyNav
14454          */
14455         disable: function(){
14456                 if(!this.disabled){
14457                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14458                 this.el.un("keydown", this.relay);
14459             }else{
14460                 this.el.un("keydown", this.prepareEvent);
14461                 this.el.un("keypress", this.relay);
14462             }
14463                     this.disabled = true;
14464                 }
14465         }
14466 };/*
14467  * Based on:
14468  * Ext JS Library 1.1.1
14469  * Copyright(c) 2006-2007, Ext JS, LLC.
14470  *
14471  * Originally Released Under LGPL - original licence link has changed is not relivant.
14472  *
14473  * Fork - LGPL
14474  * <script type="text/javascript">
14475  */
14476
14477  
14478 /**
14479  * @class Roo.KeyMap
14480  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14481  * The constructor accepts the same config object as defined by {@link #addBinding}.
14482  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14483  * combination it will call the function with this signature (if the match is a multi-key
14484  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14485  * A KeyMap can also handle a string representation of keys.<br />
14486  * Usage:
14487  <pre><code>
14488 // map one key by key code
14489 var map = new Roo.KeyMap("my-element", {
14490     key: 13, // or Roo.EventObject.ENTER
14491     fn: myHandler,
14492     scope: myObject
14493 });
14494
14495 // map multiple keys to one action by string
14496 var map = new Roo.KeyMap("my-element", {
14497     key: "a\r\n\t",
14498     fn: myHandler,
14499     scope: myObject
14500 });
14501
14502 // map multiple keys to multiple actions by strings and array of codes
14503 var map = new Roo.KeyMap("my-element", [
14504     {
14505         key: [10,13],
14506         fn: function(){ alert("Return was pressed"); }
14507     }, {
14508         key: "abc",
14509         fn: function(){ alert('a, b or c was pressed'); }
14510     }, {
14511         key: "\t",
14512         ctrl:true,
14513         shift:true,
14514         fn: function(){ alert('Control + shift + tab was pressed.'); }
14515     }
14516 ]);
14517 </code></pre>
14518  * <b>Note: A KeyMap starts enabled</b>
14519  * @constructor
14520  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14521  * @param {Object} config The config (see {@link #addBinding})
14522  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14523  */
14524 Roo.KeyMap = function(el, config, eventName){
14525     this.el  = Roo.get(el);
14526     this.eventName = eventName || "keydown";
14527     this.bindings = [];
14528     if(config){
14529         this.addBinding(config);
14530     }
14531     this.enable();
14532 };
14533
14534 Roo.KeyMap.prototype = {
14535     /**
14536      * True to stop the event from bubbling and prevent the default browser action if the
14537      * key was handled by the KeyMap (defaults to false)
14538      * @type Boolean
14539      */
14540     stopEvent : false,
14541
14542     /**
14543      * Add a new binding to this KeyMap. The following config object properties are supported:
14544      * <pre>
14545 Property    Type             Description
14546 ----------  ---------------  ----------------------------------------------------------------------
14547 key         String/Array     A single keycode or an array of keycodes to handle
14548 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14549 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14550 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14551 fn          Function         The function to call when KeyMap finds the expected key combination
14552 scope       Object           The scope of the callback function
14553 </pre>
14554      *
14555      * Usage:
14556      * <pre><code>
14557 // Create a KeyMap
14558 var map = new Roo.KeyMap(document, {
14559     key: Roo.EventObject.ENTER,
14560     fn: handleKey,
14561     scope: this
14562 });
14563
14564 //Add a new binding to the existing KeyMap later
14565 map.addBinding({
14566     key: 'abc',
14567     shift: true,
14568     fn: handleKey,
14569     scope: this
14570 });
14571 </code></pre>
14572      * @param {Object/Array} config A single KeyMap config or an array of configs
14573      */
14574         addBinding : function(config){
14575         if(config instanceof Array){
14576             for(var i = 0, len = config.length; i < len; i++){
14577                 this.addBinding(config[i]);
14578             }
14579             return;
14580         }
14581         var keyCode = config.key,
14582             shift = config.shift, 
14583             ctrl = config.ctrl, 
14584             alt = config.alt,
14585             fn = config.fn,
14586             scope = config.scope;
14587         if(typeof keyCode == "string"){
14588             var ks = [];
14589             var keyString = keyCode.toUpperCase();
14590             for(var j = 0, len = keyString.length; j < len; j++){
14591                 ks.push(keyString.charCodeAt(j));
14592             }
14593             keyCode = ks;
14594         }
14595         var keyArray = keyCode instanceof Array;
14596         var handler = function(e){
14597             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14598                 var k = e.getKey();
14599                 if(keyArray){
14600                     for(var i = 0, len = keyCode.length; i < len; i++){
14601                         if(keyCode[i] == k){
14602                           if(this.stopEvent){
14603                               e.stopEvent();
14604                           }
14605                           fn.call(scope || window, k, e);
14606                           return;
14607                         }
14608                     }
14609                 }else{
14610                     if(k == keyCode){
14611                         if(this.stopEvent){
14612                            e.stopEvent();
14613                         }
14614                         fn.call(scope || window, k, e);
14615                     }
14616                 }
14617             }
14618         };
14619         this.bindings.push(handler);  
14620         },
14621
14622     /**
14623      * Shorthand for adding a single key listener
14624      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14625      * following options:
14626      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14627      * @param {Function} fn The function to call
14628      * @param {Object} scope (optional) The scope of the function
14629      */
14630     on : function(key, fn, scope){
14631         var keyCode, shift, ctrl, alt;
14632         if(typeof key == "object" && !(key instanceof Array)){
14633             keyCode = key.key;
14634             shift = key.shift;
14635             ctrl = key.ctrl;
14636             alt = key.alt;
14637         }else{
14638             keyCode = key;
14639         }
14640         this.addBinding({
14641             key: keyCode,
14642             shift: shift,
14643             ctrl: ctrl,
14644             alt: alt,
14645             fn: fn,
14646             scope: scope
14647         })
14648     },
14649
14650     // private
14651     handleKeyDown : function(e){
14652             if(this.enabled){ //just in case
14653             var b = this.bindings;
14654             for(var i = 0, len = b.length; i < len; i++){
14655                 b[i].call(this, e);
14656             }
14657             }
14658         },
14659         
14660         /**
14661          * Returns true if this KeyMap is enabled
14662          * @return {Boolean} 
14663          */
14664         isEnabled : function(){
14665             return this.enabled;  
14666         },
14667         
14668         /**
14669          * Enables this KeyMap
14670          */
14671         enable: function(){
14672                 if(!this.enabled){
14673                     this.el.on(this.eventName, this.handleKeyDown, this);
14674                     this.enabled = true;
14675                 }
14676         },
14677
14678         /**
14679          * Disable this KeyMap
14680          */
14681         disable: function(){
14682                 if(this.enabled){
14683                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14684                     this.enabled = false;
14685                 }
14686         }
14687 };/*
14688  * Based on:
14689  * Ext JS Library 1.1.1
14690  * Copyright(c) 2006-2007, Ext JS, LLC.
14691  *
14692  * Originally Released Under LGPL - original licence link has changed is not relivant.
14693  *
14694  * Fork - LGPL
14695  * <script type="text/javascript">
14696  */
14697
14698  
14699 /**
14700  * @class Roo.util.TextMetrics
14701  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14702  * wide, in pixels, a given block of text will be.
14703  * @singleton
14704  */
14705 Roo.util.TextMetrics = function(){
14706     var shared;
14707     return {
14708         /**
14709          * Measures the size of the specified text
14710          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14711          * that can affect the size of the rendered text
14712          * @param {String} text The text to measure
14713          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14714          * in order to accurately measure the text height
14715          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14716          */
14717         measure : function(el, text, fixedWidth){
14718             if(!shared){
14719                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14720             }
14721             shared.bind(el);
14722             shared.setFixedWidth(fixedWidth || 'auto');
14723             return shared.getSize(text);
14724         },
14725
14726         /**
14727          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14728          * the overhead of multiple calls to initialize the style properties on each measurement.
14729          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14730          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14731          * in order to accurately measure the text height
14732          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14733          */
14734         createInstance : function(el, fixedWidth){
14735             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14736         }
14737     };
14738 }();
14739
14740  
14741
14742 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14743     var ml = new Roo.Element(document.createElement('div'));
14744     document.body.appendChild(ml.dom);
14745     ml.position('absolute');
14746     ml.setLeftTop(-1000, -1000);
14747     ml.hide();
14748
14749     if(fixedWidth){
14750         ml.setWidth(fixedWidth);
14751     }
14752      
14753     var instance = {
14754         /**
14755          * Returns the size of the specified text based on the internal element's style and width properties
14756          * @memberOf Roo.util.TextMetrics.Instance#
14757          * @param {String} text The text to measure
14758          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14759          */
14760         getSize : function(text){
14761             ml.update(text);
14762             var s = ml.getSize();
14763             ml.update('');
14764             return s;
14765         },
14766
14767         /**
14768          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14769          * that can affect the size of the rendered text
14770          * @memberOf Roo.util.TextMetrics.Instance#
14771          * @param {String/HTMLElement} el The element, dom node or id
14772          */
14773         bind : function(el){
14774             ml.setStyle(
14775                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14776             );
14777         },
14778
14779         /**
14780          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14781          * to set a fixed width in order to accurately measure the text height.
14782          * @memberOf Roo.util.TextMetrics.Instance#
14783          * @param {Number} width The width to set on the element
14784          */
14785         setFixedWidth : function(width){
14786             ml.setWidth(width);
14787         },
14788
14789         /**
14790          * Returns the measured width of the specified text
14791          * @memberOf Roo.util.TextMetrics.Instance#
14792          * @param {String} text The text to measure
14793          * @return {Number} width The width in pixels
14794          */
14795         getWidth : function(text){
14796             ml.dom.style.width = 'auto';
14797             return this.getSize(text).width;
14798         },
14799
14800         /**
14801          * Returns the measured height of the specified text.  For multiline text, be sure to call
14802          * {@link #setFixedWidth} if necessary.
14803          * @memberOf Roo.util.TextMetrics.Instance#
14804          * @param {String} text The text to measure
14805          * @return {Number} height The height in pixels
14806          */
14807         getHeight : function(text){
14808             return this.getSize(text).height;
14809         }
14810     };
14811
14812     instance.bind(bindTo);
14813
14814     return instance;
14815 };
14816
14817 // backwards compat
14818 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14819  * Based on:
14820  * Ext JS Library 1.1.1
14821  * Copyright(c) 2006-2007, Ext JS, LLC.
14822  *
14823  * Originally Released Under LGPL - original licence link has changed is not relivant.
14824  *
14825  * Fork - LGPL
14826  * <script type="text/javascript">
14827  */
14828
14829 /**
14830  * @class Roo.state.Provider
14831  * Abstract base class for state provider implementations. This class provides methods
14832  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14833  * Provider interface.
14834  */
14835 Roo.state.Provider = function(){
14836     /**
14837      * @event statechange
14838      * Fires when a state change occurs.
14839      * @param {Provider} this This state provider
14840      * @param {String} key The state key which was changed
14841      * @param {String} value The encoded value for the state
14842      */
14843     this.addEvents({
14844         "statechange": true
14845     });
14846     this.state = {};
14847     Roo.state.Provider.superclass.constructor.call(this);
14848 };
14849 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14850     /**
14851      * Returns the current value for a key
14852      * @param {String} name The key name
14853      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14854      * @return {Mixed} The state data
14855      */
14856     get : function(name, defaultValue){
14857         return typeof this.state[name] == "undefined" ?
14858             defaultValue : this.state[name];
14859     },
14860     
14861     /**
14862      * Clears a value from the state
14863      * @param {String} name The key name
14864      */
14865     clear : function(name){
14866         delete this.state[name];
14867         this.fireEvent("statechange", this, name, null);
14868     },
14869     
14870     /**
14871      * Sets the value for a key
14872      * @param {String} name The key name
14873      * @param {Mixed} value The value to set
14874      */
14875     set : function(name, value){
14876         this.state[name] = value;
14877         this.fireEvent("statechange", this, name, value);
14878     },
14879     
14880     /**
14881      * Decodes a string previously encoded with {@link #encodeValue}.
14882      * @param {String} value The value to decode
14883      * @return {Mixed} The decoded value
14884      */
14885     decodeValue : function(cookie){
14886         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14887         var matches = re.exec(unescape(cookie));
14888         if(!matches || !matches[1]) {
14889             return; // non state cookie
14890         }
14891         var type = matches[1];
14892         var v = matches[2];
14893         switch(type){
14894             case "n":
14895                 return parseFloat(v);
14896             case "d":
14897                 return new Date(Date.parse(v));
14898             case "b":
14899                 return (v == "1");
14900             case "a":
14901                 var all = [];
14902                 var values = v.split("^");
14903                 for(var i = 0, len = values.length; i < len; i++){
14904                     all.push(this.decodeValue(values[i]));
14905                 }
14906                 return all;
14907            case "o":
14908                 var all = {};
14909                 var values = v.split("^");
14910                 for(var i = 0, len = values.length; i < len; i++){
14911                     var kv = values[i].split("=");
14912                     all[kv[0]] = this.decodeValue(kv[1]);
14913                 }
14914                 return all;
14915            default:
14916                 return v;
14917         }
14918     },
14919     
14920     /**
14921      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14922      * @param {Mixed} value The value to encode
14923      * @return {String} The encoded value
14924      */
14925     encodeValue : function(v){
14926         var enc;
14927         if(typeof v == "number"){
14928             enc = "n:" + v;
14929         }else if(typeof v == "boolean"){
14930             enc = "b:" + (v ? "1" : "0");
14931         }else if(v instanceof Date){
14932             enc = "d:" + v.toGMTString();
14933         }else if(v instanceof Array){
14934             var flat = "";
14935             for(var i = 0, len = v.length; i < len; i++){
14936                 flat += this.encodeValue(v[i]);
14937                 if(i != len-1) {
14938                     flat += "^";
14939                 }
14940             }
14941             enc = "a:" + flat;
14942         }else if(typeof v == "object"){
14943             var flat = "";
14944             for(var key in v){
14945                 if(typeof v[key] != "function"){
14946                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14947                 }
14948             }
14949             enc = "o:" + flat.substring(0, flat.length-1);
14950         }else{
14951             enc = "s:" + v;
14952         }
14953         return escape(enc);        
14954     }
14955 });
14956
14957 /*
14958  * Based on:
14959  * Ext JS Library 1.1.1
14960  * Copyright(c) 2006-2007, Ext JS, LLC.
14961  *
14962  * Originally Released Under LGPL - original licence link has changed is not relivant.
14963  *
14964  * Fork - LGPL
14965  * <script type="text/javascript">
14966  */
14967 /**
14968  * @class Roo.state.Manager
14969  * This is the global state manager. By default all components that are "state aware" check this class
14970  * for state information if you don't pass them a custom state provider. In order for this class
14971  * to be useful, it must be initialized with a provider when your application initializes.
14972  <pre><code>
14973 // in your initialization function
14974 init : function(){
14975    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14976    ...
14977    // supposed you have a {@link Roo.BorderLayout}
14978    var layout = new Roo.BorderLayout(...);
14979    layout.restoreState();
14980    // or a {Roo.BasicDialog}
14981    var dialog = new Roo.BasicDialog(...);
14982    dialog.restoreState();
14983  </code></pre>
14984  * @singleton
14985  */
14986 Roo.state.Manager = function(){
14987     var provider = new Roo.state.Provider();
14988     
14989     return {
14990         /**
14991          * Configures the default state provider for your application
14992          * @param {Provider} stateProvider The state provider to set
14993          */
14994         setProvider : function(stateProvider){
14995             provider = stateProvider;
14996         },
14997         
14998         /**
14999          * Returns the current value for a key
15000          * @param {String} name The key name
15001          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15002          * @return {Mixed} The state data
15003          */
15004         get : function(key, defaultValue){
15005             return provider.get(key, defaultValue);
15006         },
15007         
15008         /**
15009          * Sets the value for a key
15010          * @param {String} name The key name
15011          * @param {Mixed} value The state data
15012          */
15013          set : function(key, value){
15014             provider.set(key, value);
15015         },
15016         
15017         /**
15018          * Clears a value from the state
15019          * @param {String} name The key name
15020          */
15021         clear : function(key){
15022             provider.clear(key);
15023         },
15024         
15025         /**
15026          * Gets the currently configured state provider
15027          * @return {Provider} The state provider
15028          */
15029         getProvider : function(){
15030             return provider;
15031         }
15032     };
15033 }();
15034 /*
15035  * Based on:
15036  * Ext JS Library 1.1.1
15037  * Copyright(c) 2006-2007, Ext JS, LLC.
15038  *
15039  * Originally Released Under LGPL - original licence link has changed is not relivant.
15040  *
15041  * Fork - LGPL
15042  * <script type="text/javascript">
15043  */
15044 /**
15045  * @class Roo.state.CookieProvider
15046  * @extends Roo.state.Provider
15047  * The default Provider implementation which saves state via cookies.
15048  * <br />Usage:
15049  <pre><code>
15050    var cp = new Roo.state.CookieProvider({
15051        path: "/cgi-bin/",
15052        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15053        domain: "roojs.com"
15054    })
15055    Roo.state.Manager.setProvider(cp);
15056  </code></pre>
15057  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15058  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15059  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15060  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15061  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15062  * domain the page is running on including the 'www' like 'www.roojs.com')
15063  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15064  * @constructor
15065  * Create a new CookieProvider
15066  * @param {Object} config The configuration object
15067  */
15068 Roo.state.CookieProvider = function(config){
15069     Roo.state.CookieProvider.superclass.constructor.call(this);
15070     this.path = "/";
15071     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15072     this.domain = null;
15073     this.secure = false;
15074     Roo.apply(this, config);
15075     this.state = this.readCookies();
15076 };
15077
15078 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15079     // private
15080     set : function(name, value){
15081         if(typeof value == "undefined" || value === null){
15082             this.clear(name);
15083             return;
15084         }
15085         this.setCookie(name, value);
15086         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15087     },
15088
15089     // private
15090     clear : function(name){
15091         this.clearCookie(name);
15092         Roo.state.CookieProvider.superclass.clear.call(this, name);
15093     },
15094
15095     // private
15096     readCookies : function(){
15097         var cookies = {};
15098         var c = document.cookie + ";";
15099         var re = /\s?(.*?)=(.*?);/g;
15100         var matches;
15101         while((matches = re.exec(c)) != null){
15102             var name = matches[1];
15103             var value = matches[2];
15104             if(name && name.substring(0,3) == "ys-"){
15105                 cookies[name.substr(3)] = this.decodeValue(value);
15106             }
15107         }
15108         return cookies;
15109     },
15110
15111     // private
15112     setCookie : function(name, value){
15113         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15114            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15115            ((this.path == null) ? "" : ("; path=" + this.path)) +
15116            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15117            ((this.secure == true) ? "; secure" : "");
15118     },
15119
15120     // private
15121     clearCookie : function(name){
15122         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15123            ((this.path == null) ? "" : ("; path=" + this.path)) +
15124            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15125            ((this.secure == true) ? "; secure" : "");
15126     }
15127 });/*
15128  * Based on:
15129  * Ext JS Library 1.1.1
15130  * Copyright(c) 2006-2007, Ext JS, LLC.
15131  *
15132  * Originally Released Under LGPL - original licence link has changed is not relivant.
15133  *
15134  * Fork - LGPL
15135  * <script type="text/javascript">
15136  */
15137  
15138
15139 /**
15140  * @class Roo.ComponentMgr
15141  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15142  * @singleton
15143  */
15144 Roo.ComponentMgr = function(){
15145     var all = new Roo.util.MixedCollection();
15146
15147     return {
15148         /**
15149          * Registers a component.
15150          * @param {Roo.Component} c The component
15151          */
15152         register : function(c){
15153             all.add(c);
15154         },
15155
15156         /**
15157          * Unregisters a component.
15158          * @param {Roo.Component} c The component
15159          */
15160         unregister : function(c){
15161             all.remove(c);
15162         },
15163
15164         /**
15165          * Returns a component by id
15166          * @param {String} id The component id
15167          */
15168         get : function(id){
15169             return all.get(id);
15170         },
15171
15172         /**
15173          * Registers a function that will be called when a specified component is added to ComponentMgr
15174          * @param {String} id The component id
15175          * @param {Funtction} fn The callback function
15176          * @param {Object} scope The scope of the callback
15177          */
15178         onAvailable : function(id, fn, scope){
15179             all.on("add", function(index, o){
15180                 if(o.id == id){
15181                     fn.call(scope || o, o);
15182                     all.un("add", fn, scope);
15183                 }
15184             });
15185         }
15186     };
15187 }();/*
15188  * Based on:
15189  * Ext JS Library 1.1.1
15190  * Copyright(c) 2006-2007, Ext JS, LLC.
15191  *
15192  * Originally Released Under LGPL - original licence link has changed is not relivant.
15193  *
15194  * Fork - LGPL
15195  * <script type="text/javascript">
15196  */
15197  
15198 /**
15199  * @class Roo.Component
15200  * @extends Roo.util.Observable
15201  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15202  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15203  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15204  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15205  * All visual components (widgets) that require rendering into a layout should subclass Component.
15206  * @constructor
15207  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15208  * 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
15209  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15210  */
15211 Roo.Component = function(config){
15212     config = config || {};
15213     if(config.tagName || config.dom || typeof config == "string"){ // element object
15214         config = {el: config, id: config.id || config};
15215     }
15216     this.initialConfig = config;
15217
15218     Roo.apply(this, config);
15219     this.addEvents({
15220         /**
15221          * @event disable
15222          * Fires after the component is disabled.
15223              * @param {Roo.Component} this
15224              */
15225         disable : true,
15226         /**
15227          * @event enable
15228          * Fires after the component is enabled.
15229              * @param {Roo.Component} this
15230              */
15231         enable : true,
15232         /**
15233          * @event beforeshow
15234          * Fires before the component is shown.  Return false to stop the show.
15235              * @param {Roo.Component} this
15236              */
15237         beforeshow : true,
15238         /**
15239          * @event show
15240          * Fires after the component is shown.
15241              * @param {Roo.Component} this
15242              */
15243         show : true,
15244         /**
15245          * @event beforehide
15246          * Fires before the component is hidden. Return false to stop the hide.
15247              * @param {Roo.Component} this
15248              */
15249         beforehide : true,
15250         /**
15251          * @event hide
15252          * Fires after the component is hidden.
15253              * @param {Roo.Component} this
15254              */
15255         hide : true,
15256         /**
15257          * @event beforerender
15258          * Fires before the component is rendered. Return false to stop the render.
15259              * @param {Roo.Component} this
15260              */
15261         beforerender : true,
15262         /**
15263          * @event render
15264          * Fires after the component is rendered.
15265              * @param {Roo.Component} this
15266              */
15267         render : true,
15268         /**
15269          * @event beforedestroy
15270          * Fires before the component is destroyed. Return false to stop the destroy.
15271              * @param {Roo.Component} this
15272              */
15273         beforedestroy : true,
15274         /**
15275          * @event destroy
15276          * Fires after the component is destroyed.
15277              * @param {Roo.Component} this
15278              */
15279         destroy : true
15280     });
15281     if(!this.id){
15282         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15283     }
15284     Roo.ComponentMgr.register(this);
15285     Roo.Component.superclass.constructor.call(this);
15286     this.initComponent();
15287     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15288         this.render(this.renderTo);
15289         delete this.renderTo;
15290     }
15291 };
15292
15293 /** @private */
15294 Roo.Component.AUTO_ID = 1000;
15295
15296 Roo.extend(Roo.Component, Roo.util.Observable, {
15297     /**
15298      * @scope Roo.Component.prototype
15299      * @type {Boolean}
15300      * true if this component is hidden. Read-only.
15301      */
15302     hidden : false,
15303     /**
15304      * @type {Boolean}
15305      * true if this component is disabled. Read-only.
15306      */
15307     disabled : false,
15308     /**
15309      * @type {Boolean}
15310      * true if this component has been rendered. Read-only.
15311      */
15312     rendered : false,
15313     
15314     /** @cfg {String} disableClass
15315      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15316      */
15317     disabledClass : "x-item-disabled",
15318         /** @cfg {Boolean} allowDomMove
15319          * Whether the component can move the Dom node when rendering (defaults to true).
15320          */
15321     allowDomMove : true,
15322     /** @cfg {String} hideMode (display|visibility)
15323      * How this component should hidden. Supported values are
15324      * "visibility" (css visibility), "offsets" (negative offset position) and
15325      * "display" (css display) - defaults to "display".
15326      */
15327     hideMode: 'display',
15328
15329     /** @private */
15330     ctype : "Roo.Component",
15331
15332     /**
15333      * @cfg {String} actionMode 
15334      * which property holds the element that used for  hide() / show() / disable() / enable()
15335      * default is 'el' 
15336      */
15337     actionMode : "el",
15338
15339     /** @private */
15340     getActionEl : function(){
15341         return this[this.actionMode];
15342     },
15343
15344     initComponent : Roo.emptyFn,
15345     /**
15346      * If this is a lazy rendering component, render it to its container element.
15347      * @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.
15348      */
15349     render : function(container, position){
15350         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15351             if(!container && this.el){
15352                 this.el = Roo.get(this.el);
15353                 container = this.el.dom.parentNode;
15354                 this.allowDomMove = false;
15355             }
15356             this.container = Roo.get(container);
15357             this.rendered = true;
15358             if(position !== undefined){
15359                 if(typeof position == 'number'){
15360                     position = this.container.dom.childNodes[position];
15361                 }else{
15362                     position = Roo.getDom(position);
15363                 }
15364             }
15365             this.onRender(this.container, position || null);
15366             if(this.cls){
15367                 this.el.addClass(this.cls);
15368                 delete this.cls;
15369             }
15370             if(this.style){
15371                 this.el.applyStyles(this.style);
15372                 delete this.style;
15373             }
15374             this.fireEvent("render", this);
15375             this.afterRender(this.container);
15376             if(this.hidden){
15377                 this.hide();
15378             }
15379             if(this.disabled){
15380                 this.disable();
15381             }
15382         }
15383         return this;
15384     },
15385
15386     /** @private */
15387     // default function is not really useful
15388     onRender : function(ct, position){
15389         if(this.el){
15390             this.el = Roo.get(this.el);
15391             if(this.allowDomMove !== false){
15392                 ct.dom.insertBefore(this.el.dom, position);
15393             }
15394         }
15395     },
15396
15397     /** @private */
15398     getAutoCreate : function(){
15399         var cfg = typeof this.autoCreate == "object" ?
15400                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15401         if(this.id && !cfg.id){
15402             cfg.id = this.id;
15403         }
15404         return cfg;
15405     },
15406
15407     /** @private */
15408     afterRender : Roo.emptyFn,
15409
15410     /**
15411      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15412      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15413      */
15414     destroy : function(){
15415         if(this.fireEvent("beforedestroy", this) !== false){
15416             this.purgeListeners();
15417             this.beforeDestroy();
15418             if(this.rendered){
15419                 this.el.removeAllListeners();
15420                 this.el.remove();
15421                 if(this.actionMode == "container"){
15422                     this.container.remove();
15423                 }
15424             }
15425             this.onDestroy();
15426             Roo.ComponentMgr.unregister(this);
15427             this.fireEvent("destroy", this);
15428         }
15429     },
15430
15431         /** @private */
15432     beforeDestroy : function(){
15433
15434     },
15435
15436         /** @private */
15437         onDestroy : function(){
15438
15439     },
15440
15441     /**
15442      * Returns the underlying {@link Roo.Element}.
15443      * @return {Roo.Element} The element
15444      */
15445     getEl : function(){
15446         return this.el;
15447     },
15448
15449     /**
15450      * Returns the id of this component.
15451      * @return {String}
15452      */
15453     getId : function(){
15454         return this.id;
15455     },
15456
15457     /**
15458      * Try to focus this component.
15459      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15460      * @return {Roo.Component} this
15461      */
15462     focus : function(selectText){
15463         if(this.rendered){
15464             this.el.focus();
15465             if(selectText === true){
15466                 this.el.dom.select();
15467             }
15468         }
15469         return this;
15470     },
15471
15472     /** @private */
15473     blur : function(){
15474         if(this.rendered){
15475             this.el.blur();
15476         }
15477         return this;
15478     },
15479
15480     /**
15481      * Disable this component.
15482      * @return {Roo.Component} this
15483      */
15484     disable : function(){
15485         if(this.rendered){
15486             this.onDisable();
15487         }
15488         this.disabled = true;
15489         this.fireEvent("disable", this);
15490         return this;
15491     },
15492
15493         // private
15494     onDisable : function(){
15495         this.getActionEl().addClass(this.disabledClass);
15496         this.el.dom.disabled = true;
15497     },
15498
15499     /**
15500      * Enable this component.
15501      * @return {Roo.Component} this
15502      */
15503     enable : function(){
15504         if(this.rendered){
15505             this.onEnable();
15506         }
15507         this.disabled = false;
15508         this.fireEvent("enable", this);
15509         return this;
15510     },
15511
15512         // private
15513     onEnable : function(){
15514         this.getActionEl().removeClass(this.disabledClass);
15515         this.el.dom.disabled = false;
15516     },
15517
15518     /**
15519      * Convenience function for setting disabled/enabled by boolean.
15520      * @param {Boolean} disabled
15521      */
15522     setDisabled : function(disabled){
15523         this[disabled ? "disable" : "enable"]();
15524     },
15525
15526     /**
15527      * Show this component.
15528      * @return {Roo.Component} this
15529      */
15530     show: function(){
15531         if(this.fireEvent("beforeshow", this) !== false){
15532             this.hidden = false;
15533             if(this.rendered){
15534                 this.onShow();
15535             }
15536             this.fireEvent("show", this);
15537         }
15538         return this;
15539     },
15540
15541     // private
15542     onShow : function(){
15543         var ae = this.getActionEl();
15544         if(this.hideMode == 'visibility'){
15545             ae.dom.style.visibility = "visible";
15546         }else if(this.hideMode == 'offsets'){
15547             ae.removeClass('x-hidden');
15548         }else{
15549             ae.dom.style.display = "";
15550         }
15551     },
15552
15553     /**
15554      * Hide this component.
15555      * @return {Roo.Component} this
15556      */
15557     hide: function(){
15558         if(this.fireEvent("beforehide", this) !== false){
15559             this.hidden = true;
15560             if(this.rendered){
15561                 this.onHide();
15562             }
15563             this.fireEvent("hide", this);
15564         }
15565         return this;
15566     },
15567
15568     // private
15569     onHide : function(){
15570         var ae = this.getActionEl();
15571         if(this.hideMode == 'visibility'){
15572             ae.dom.style.visibility = "hidden";
15573         }else if(this.hideMode == 'offsets'){
15574             ae.addClass('x-hidden');
15575         }else{
15576             ae.dom.style.display = "none";
15577         }
15578     },
15579
15580     /**
15581      * Convenience function to hide or show this component by boolean.
15582      * @param {Boolean} visible True to show, false to hide
15583      * @return {Roo.Component} this
15584      */
15585     setVisible: function(visible){
15586         if(visible) {
15587             this.show();
15588         }else{
15589             this.hide();
15590         }
15591         return this;
15592     },
15593
15594     /**
15595      * Returns true if this component is visible.
15596      */
15597     isVisible : function(){
15598         return this.getActionEl().isVisible();
15599     },
15600
15601     cloneConfig : function(overrides){
15602         overrides = overrides || {};
15603         var id = overrides.id || Roo.id();
15604         var cfg = Roo.applyIf(overrides, this.initialConfig);
15605         cfg.id = id; // prevent dup id
15606         return new this.constructor(cfg);
15607     }
15608 });/*
15609  * Based on:
15610  * Ext JS Library 1.1.1
15611  * Copyright(c) 2006-2007, Ext JS, LLC.
15612  *
15613  * Originally Released Under LGPL - original licence link has changed is not relivant.
15614  *
15615  * Fork - LGPL
15616  * <script type="text/javascript">
15617  */
15618
15619 /**
15620  * @class Roo.BoxComponent
15621  * @extends Roo.Component
15622  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15623  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15624  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15625  * layout containers.
15626  * @constructor
15627  * @param {Roo.Element/String/Object} config The configuration options.
15628  */
15629 Roo.BoxComponent = function(config){
15630     Roo.Component.call(this, config);
15631     this.addEvents({
15632         /**
15633          * @event resize
15634          * Fires after the component is resized.
15635              * @param {Roo.Component} this
15636              * @param {Number} adjWidth The box-adjusted width that was set
15637              * @param {Number} adjHeight The box-adjusted height that was set
15638              * @param {Number} rawWidth The width that was originally specified
15639              * @param {Number} rawHeight The height that was originally specified
15640              */
15641         resize : true,
15642         /**
15643          * @event move
15644          * Fires after the component is moved.
15645              * @param {Roo.Component} this
15646              * @param {Number} x The new x position
15647              * @param {Number} y The new y position
15648              */
15649         move : true
15650     });
15651 };
15652
15653 Roo.extend(Roo.BoxComponent, Roo.Component, {
15654     // private, set in afterRender to signify that the component has been rendered
15655     boxReady : false,
15656     // private, used to defer height settings to subclasses
15657     deferHeight: false,
15658     /** @cfg {Number} width
15659      * width (optional) size of component
15660      */
15661      /** @cfg {Number} height
15662      * height (optional) size of component
15663      */
15664      
15665     /**
15666      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15667      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15668      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15669      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15670      * @return {Roo.BoxComponent} this
15671      */
15672     setSize : function(w, h){
15673         // support for standard size objects
15674         if(typeof w == 'object'){
15675             h = w.height;
15676             w = w.width;
15677         }
15678         // not rendered
15679         if(!this.boxReady){
15680             this.width = w;
15681             this.height = h;
15682             return this;
15683         }
15684
15685         // prevent recalcs when not needed
15686         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15687             return this;
15688         }
15689         this.lastSize = {width: w, height: h};
15690
15691         var adj = this.adjustSize(w, h);
15692         var aw = adj.width, ah = adj.height;
15693         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15694             var rz = this.getResizeEl();
15695             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15696                 rz.setSize(aw, ah);
15697             }else if(!this.deferHeight && ah !== undefined){
15698                 rz.setHeight(ah);
15699             }else if(aw !== undefined){
15700                 rz.setWidth(aw);
15701             }
15702             this.onResize(aw, ah, w, h);
15703             this.fireEvent('resize', this, aw, ah, w, h);
15704         }
15705         return this;
15706     },
15707
15708     /**
15709      * Gets the current size of the component's underlying element.
15710      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15711      */
15712     getSize : function(){
15713         return this.el.getSize();
15714     },
15715
15716     /**
15717      * Gets the current XY position of the component's underlying element.
15718      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15719      * @return {Array} The XY position of the element (e.g., [100, 200])
15720      */
15721     getPosition : function(local){
15722         if(local === true){
15723             return [this.el.getLeft(true), this.el.getTop(true)];
15724         }
15725         return this.xy || this.el.getXY();
15726     },
15727
15728     /**
15729      * Gets the current box measurements of the component's underlying element.
15730      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15731      * @returns {Object} box An object in the format {x, y, width, height}
15732      */
15733     getBox : function(local){
15734         var s = this.el.getSize();
15735         if(local){
15736             s.x = this.el.getLeft(true);
15737             s.y = this.el.getTop(true);
15738         }else{
15739             var xy = this.xy || this.el.getXY();
15740             s.x = xy[0];
15741             s.y = xy[1];
15742         }
15743         return s;
15744     },
15745
15746     /**
15747      * Sets the current box measurements of the component's underlying element.
15748      * @param {Object} box An object in the format {x, y, width, height}
15749      * @returns {Roo.BoxComponent} this
15750      */
15751     updateBox : function(box){
15752         this.setSize(box.width, box.height);
15753         this.setPagePosition(box.x, box.y);
15754         return this;
15755     },
15756
15757     // protected
15758     getResizeEl : function(){
15759         return this.resizeEl || this.el;
15760     },
15761
15762     // protected
15763     getPositionEl : function(){
15764         return this.positionEl || this.el;
15765     },
15766
15767     /**
15768      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15769      * This method fires the move event.
15770      * @param {Number} left The new left
15771      * @param {Number} top The new top
15772      * @returns {Roo.BoxComponent} this
15773      */
15774     setPosition : function(x, y){
15775         this.x = x;
15776         this.y = y;
15777         if(!this.boxReady){
15778             return this;
15779         }
15780         var adj = this.adjustPosition(x, y);
15781         var ax = adj.x, ay = adj.y;
15782
15783         var el = this.getPositionEl();
15784         if(ax !== undefined || ay !== undefined){
15785             if(ax !== undefined && ay !== undefined){
15786                 el.setLeftTop(ax, ay);
15787             }else if(ax !== undefined){
15788                 el.setLeft(ax);
15789             }else if(ay !== undefined){
15790                 el.setTop(ay);
15791             }
15792             this.onPosition(ax, ay);
15793             this.fireEvent('move', this, ax, ay);
15794         }
15795         return this;
15796     },
15797
15798     /**
15799      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15800      * This method fires the move event.
15801      * @param {Number} x The new x position
15802      * @param {Number} y The new y position
15803      * @returns {Roo.BoxComponent} this
15804      */
15805     setPagePosition : function(x, y){
15806         this.pageX = x;
15807         this.pageY = y;
15808         if(!this.boxReady){
15809             return;
15810         }
15811         if(x === undefined || y === undefined){ // cannot translate undefined points
15812             return;
15813         }
15814         var p = this.el.translatePoints(x, y);
15815         this.setPosition(p.left, p.top);
15816         return this;
15817     },
15818
15819     // private
15820     onRender : function(ct, position){
15821         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15822         if(this.resizeEl){
15823             this.resizeEl = Roo.get(this.resizeEl);
15824         }
15825         if(this.positionEl){
15826             this.positionEl = Roo.get(this.positionEl);
15827         }
15828     },
15829
15830     // private
15831     afterRender : function(){
15832         Roo.BoxComponent.superclass.afterRender.call(this);
15833         this.boxReady = true;
15834         this.setSize(this.width, this.height);
15835         if(this.x || this.y){
15836             this.setPosition(this.x, this.y);
15837         }
15838         if(this.pageX || this.pageY){
15839             this.setPagePosition(this.pageX, this.pageY);
15840         }
15841     },
15842
15843     /**
15844      * Force the component's size to recalculate based on the underlying element's current height and width.
15845      * @returns {Roo.BoxComponent} this
15846      */
15847     syncSize : function(){
15848         delete this.lastSize;
15849         this.setSize(this.el.getWidth(), this.el.getHeight());
15850         return this;
15851     },
15852
15853     /**
15854      * Called after the component is resized, this method is empty by default but can be implemented by any
15855      * subclass that needs to perform custom logic after a resize occurs.
15856      * @param {Number} adjWidth The box-adjusted width that was set
15857      * @param {Number} adjHeight The box-adjusted height that was set
15858      * @param {Number} rawWidth The width that was originally specified
15859      * @param {Number} rawHeight The height that was originally specified
15860      */
15861     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15862
15863     },
15864
15865     /**
15866      * Called after the component is moved, this method is empty by default but can be implemented by any
15867      * subclass that needs to perform custom logic after a move occurs.
15868      * @param {Number} x The new x position
15869      * @param {Number} y The new y position
15870      */
15871     onPosition : function(x, y){
15872
15873     },
15874
15875     // private
15876     adjustSize : function(w, h){
15877         if(this.autoWidth){
15878             w = 'auto';
15879         }
15880         if(this.autoHeight){
15881             h = 'auto';
15882         }
15883         return {width : w, height: h};
15884     },
15885
15886     // private
15887     adjustPosition : function(x, y){
15888         return {x : x, y: y};
15889     }
15890 });/*
15891  * Original code for Roojs - LGPL
15892  * <script type="text/javascript">
15893  */
15894  
15895 /**
15896  * @class Roo.XComponent
15897  * A delayed Element creator...
15898  * Or a way to group chunks of interface together.
15899  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15900  *  used in conjunction with XComponent.build() it will create an instance of each element,
15901  *  then call addxtype() to build the User interface.
15902  * 
15903  * Mypart.xyx = new Roo.XComponent({
15904
15905     parent : 'Mypart.xyz', // empty == document.element.!!
15906     order : '001',
15907     name : 'xxxx'
15908     region : 'xxxx'
15909     disabled : function() {} 
15910      
15911     tree : function() { // return an tree of xtype declared components
15912         var MODULE = this;
15913         return 
15914         {
15915             xtype : 'NestedLayoutPanel',
15916             // technicall
15917         }
15918      ]
15919  *})
15920  *
15921  *
15922  * It can be used to build a big heiracy, with parent etc.
15923  * or you can just use this to render a single compoent to a dom element
15924  * MYPART.render(Roo.Element | String(id) | dom_element )
15925  *
15926  *
15927  * Usage patterns.
15928  *
15929  * Classic Roo
15930  *
15931  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15932  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15933  *
15934  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15935  *
15936  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15937  * - if mulitple topModules exist, the last one is defined as the top module.
15938  *
15939  * Embeded Roo
15940  * 
15941  * When the top level or multiple modules are to embedded into a existing HTML page,
15942  * the parent element can container '#id' of the element where the module will be drawn.
15943  *
15944  * Bootstrap Roo
15945  *
15946  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15947  * it relies more on a include mechanism, where sub modules are included into an outer page.
15948  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15949  * 
15950  * Bootstrap Roo Included elements
15951  *
15952  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15953  * hence confusing the component builder as it thinks there are multiple top level elements. 
15954  *
15955  * 
15956  * 
15957  * @extends Roo.util.Observable
15958  * @constructor
15959  * @param cfg {Object} configuration of component
15960  * 
15961  */
15962 Roo.XComponent = function(cfg) {
15963     Roo.apply(this, cfg);
15964     this.addEvents({ 
15965         /**
15966              * @event built
15967              * Fires when this the componnt is built
15968              * @param {Roo.XComponent} c the component
15969              */
15970         'built' : true
15971         
15972     });
15973     this.region = this.region || 'center'; // default..
15974     Roo.XComponent.register(this);
15975     this.modules = false;
15976     this.el = false; // where the layout goes..
15977     
15978     
15979 }
15980 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15981     /**
15982      * @property el
15983      * The created element (with Roo.factory())
15984      * @type {Roo.Layout}
15985      */
15986     el  : false,
15987     
15988     /**
15989      * @property el
15990      * for BC  - use el in new code
15991      * @type {Roo.Layout}
15992      */
15993     panel : false,
15994     
15995     /**
15996      * @property layout
15997      * for BC  - use el in new code
15998      * @type {Roo.Layout}
15999      */
16000     layout : false,
16001     
16002      /**
16003      * @cfg {Function|boolean} disabled
16004      * If this module is disabled by some rule, return true from the funtion
16005      */
16006     disabled : false,
16007     
16008     /**
16009      * @cfg {String} parent 
16010      * Name of parent element which it get xtype added to..
16011      */
16012     parent: false,
16013     
16014     /**
16015      * @cfg {String} order
16016      * Used to set the order in which elements are created (usefull for multiple tabs)
16017      */
16018     
16019     order : false,
16020     /**
16021      * @cfg {String} name
16022      * String to display while loading.
16023      */
16024     name : false,
16025     /**
16026      * @cfg {String} region
16027      * Region to render component to (defaults to center)
16028      */
16029     region : 'center',
16030     
16031     /**
16032      * @cfg {Array} items
16033      * A single item array - the first element is the root of the tree..
16034      * It's done this way to stay compatible with the Xtype system...
16035      */
16036     items : false,
16037     
16038     /**
16039      * @property _tree
16040      * The method that retuns the tree of parts that make up this compoennt 
16041      * @type {function}
16042      */
16043     _tree  : false,
16044     
16045      /**
16046      * render
16047      * render element to dom or tree
16048      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16049      */
16050     
16051     render : function(el)
16052     {
16053         
16054         el = el || false;
16055         var hp = this.parent ? 1 : 0;
16056         Roo.debug &&  Roo.log(this);
16057         
16058         var tree = this._tree ? this._tree() : this.tree();
16059
16060         
16061         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16062             // if parent is a '#.....' string, then let's use that..
16063             var ename = this.parent.substr(1);
16064             this.parent = false;
16065             Roo.debug && Roo.log(ename);
16066             switch (ename) {
16067                 case 'bootstrap-body':
16068                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16069                         // this is the BorderLayout standard?
16070                        this.parent = { el : true };
16071                        break;
16072                     }
16073                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16074                         // need to insert stuff...
16075                         this.parent =  {
16076                              el : new Roo.bootstrap.layout.Border({
16077                                  el : document.body, 
16078                      
16079                                  center: {
16080                                     titlebar: false,
16081                                     autoScroll:false,
16082                                     closeOnTab: true,
16083                                     tabPosition: 'top',
16084                                       //resizeTabs: true,
16085                                     alwaysShowTabs: true,
16086                                     hideTabs: false
16087                                      //minTabWidth: 140
16088                                  }
16089                              })
16090                         
16091                          };
16092                          break;
16093                     }
16094                          
16095                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16096                         this.parent = { el :  new  Roo.bootstrap.Body() };
16097                         Roo.debug && Roo.log("setting el to doc body");
16098                          
16099                     } else {
16100                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16101                     }
16102                     break;
16103                 case 'bootstrap':
16104                     this.parent = { el : true};
16105                     // fall through
16106                 default:
16107                     el = Roo.get(ename);
16108                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16109                         this.parent = { el : true};
16110                     }
16111                     
16112                     break;
16113             }
16114                 
16115             
16116             if (!el && !this.parent) {
16117                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16118                 return;
16119             }
16120         }
16121         
16122         Roo.debug && Roo.log("EL:");
16123         Roo.debug && Roo.log(el);
16124         Roo.debug && Roo.log("this.parent.el:");
16125         Roo.debug && Roo.log(this.parent.el);
16126         
16127
16128         // altertive root elements ??? - we need a better way to indicate these.
16129         var is_alt = Roo.XComponent.is_alt ||
16130                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16131                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16132                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16133         
16134         
16135         
16136         if (!this.parent && is_alt) {
16137             //el = Roo.get(document.body);
16138             this.parent = { el : true };
16139         }
16140             
16141             
16142         
16143         if (!this.parent) {
16144             
16145             Roo.debug && Roo.log("no parent - creating one");
16146             
16147             el = el ? Roo.get(el) : false;      
16148             
16149             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16150                 
16151                 this.parent =  {
16152                     el : new Roo.bootstrap.layout.Border({
16153                         el: el || document.body,
16154                     
16155                         center: {
16156                             titlebar: false,
16157                             autoScroll:false,
16158                             closeOnTab: true,
16159                             tabPosition: 'top',
16160                              //resizeTabs: true,
16161                             alwaysShowTabs: false,
16162                             hideTabs: true,
16163                             minTabWidth: 140,
16164                             overflow: 'visible'
16165                          }
16166                      })
16167                 };
16168             } else {
16169             
16170                 // it's a top level one..
16171                 this.parent =  {
16172                     el : new Roo.BorderLayout(el || document.body, {
16173                         center: {
16174                             titlebar: false,
16175                             autoScroll:false,
16176                             closeOnTab: true,
16177                             tabPosition: 'top',
16178                              //resizeTabs: true,
16179                             alwaysShowTabs: el && hp? false :  true,
16180                             hideTabs: el || !hp ? true :  false,
16181                             minTabWidth: 140
16182                          }
16183                     })
16184                 };
16185             }
16186         }
16187         
16188         if (!this.parent.el) {
16189                 // probably an old style ctor, which has been disabled.
16190                 return;
16191
16192         }
16193                 // The 'tree' method is  '_tree now' 
16194             
16195         tree.region = tree.region || this.region;
16196         var is_body = false;
16197         if (this.parent.el === true) {
16198             // bootstrap... - body..
16199             if (el) {
16200                 tree.el = el;
16201             }
16202             this.parent.el = Roo.factory(tree);
16203             is_body = true;
16204         }
16205         
16206         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16207         this.fireEvent('built', this);
16208         
16209         this.panel = this.el;
16210         this.layout = this.panel.layout;
16211         this.parentLayout = this.parent.layout  || false;  
16212          
16213     }
16214     
16215 });
16216
16217 Roo.apply(Roo.XComponent, {
16218     /**
16219      * @property  hideProgress
16220      * true to disable the building progress bar.. usefull on single page renders.
16221      * @type Boolean
16222      */
16223     hideProgress : false,
16224     /**
16225      * @property  buildCompleted
16226      * True when the builder has completed building the interface.
16227      * @type Boolean
16228      */
16229     buildCompleted : false,
16230      
16231     /**
16232      * @property  topModule
16233      * the upper most module - uses document.element as it's constructor.
16234      * @type Object
16235      */
16236      
16237     topModule  : false,
16238       
16239     /**
16240      * @property  modules
16241      * array of modules to be created by registration system.
16242      * @type {Array} of Roo.XComponent
16243      */
16244     
16245     modules : [],
16246     /**
16247      * @property  elmodules
16248      * array of modules to be created by which use #ID 
16249      * @type {Array} of Roo.XComponent
16250      */
16251      
16252     elmodules : [],
16253
16254      /**
16255      * @property  is_alt
16256      * Is an alternative Root - normally used by bootstrap or other systems,
16257      *    where the top element in the tree can wrap 'body' 
16258      * @type {boolean}  (default false)
16259      */
16260      
16261     is_alt : false,
16262     /**
16263      * @property  build_from_html
16264      * Build elements from html - used by bootstrap HTML stuff 
16265      *    - this is cleared after build is completed
16266      * @type {boolean}    (default false)
16267      */
16268      
16269     build_from_html : false,
16270     /**
16271      * Register components to be built later.
16272      *
16273      * This solves the following issues
16274      * - Building is not done on page load, but after an authentication process has occured.
16275      * - Interface elements are registered on page load
16276      * - Parent Interface elements may not be loaded before child, so this handles that..
16277      * 
16278      *
16279      * example:
16280      * 
16281      * MyApp.register({
16282           order : '000001',
16283           module : 'Pman.Tab.projectMgr',
16284           region : 'center',
16285           parent : 'Pman.layout',
16286           disabled : false,  // or use a function..
16287         })
16288      
16289      * * @param {Object} details about module
16290      */
16291     register : function(obj) {
16292                 
16293         Roo.XComponent.event.fireEvent('register', obj);
16294         switch(typeof(obj.disabled) ) {
16295                 
16296             case 'undefined':
16297                 break;
16298             
16299             case 'function':
16300                 if ( obj.disabled() ) {
16301                         return;
16302                 }
16303                 break;
16304             
16305             default:
16306                 if (obj.disabled) {
16307                         return;
16308                 }
16309                 break;
16310         }
16311                 
16312         this.modules.push(obj);
16313          
16314     },
16315     /**
16316      * convert a string to an object..
16317      * eg. 'AAA.BBB' -> finds AAA.BBB
16318
16319      */
16320     
16321     toObject : function(str)
16322     {
16323         if (!str || typeof(str) == 'object') {
16324             return str;
16325         }
16326         if (str.substring(0,1) == '#') {
16327             return str;
16328         }
16329
16330         var ar = str.split('.');
16331         var rt, o;
16332         rt = ar.shift();
16333             /** eval:var:o */
16334         try {
16335             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16336         } catch (e) {
16337             throw "Module not found : " + str;
16338         }
16339         
16340         if (o === false) {
16341             throw "Module not found : " + str;
16342         }
16343         Roo.each(ar, function(e) {
16344             if (typeof(o[e]) == 'undefined') {
16345                 throw "Module not found : " + str;
16346             }
16347             o = o[e];
16348         });
16349         
16350         return o;
16351         
16352     },
16353     
16354     
16355     /**
16356      * move modules into their correct place in the tree..
16357      * 
16358      */
16359     preBuild : function ()
16360     {
16361         var _t = this;
16362         Roo.each(this.modules , function (obj)
16363         {
16364             Roo.XComponent.event.fireEvent('beforebuild', obj);
16365             
16366             var opar = obj.parent;
16367             try { 
16368                 obj.parent = this.toObject(opar);
16369             } catch(e) {
16370                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16371                 return;
16372             }
16373             
16374             if (!obj.parent) {
16375                 Roo.debug && Roo.log("GOT top level module");
16376                 Roo.debug && Roo.log(obj);
16377                 obj.modules = new Roo.util.MixedCollection(false, 
16378                     function(o) { return o.order + '' }
16379                 );
16380                 this.topModule = obj;
16381                 return;
16382             }
16383                         // parent is a string (usually a dom element name..)
16384             if (typeof(obj.parent) == 'string') {
16385                 this.elmodules.push(obj);
16386                 return;
16387             }
16388             if (obj.parent.constructor != Roo.XComponent) {
16389                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16390             }
16391             if (!obj.parent.modules) {
16392                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16393                     function(o) { return o.order + '' }
16394                 );
16395             }
16396             if (obj.parent.disabled) {
16397                 obj.disabled = true;
16398             }
16399             obj.parent.modules.add(obj);
16400         }, this);
16401     },
16402     
16403      /**
16404      * make a list of modules to build.
16405      * @return {Array} list of modules. 
16406      */ 
16407     
16408     buildOrder : function()
16409     {
16410         var _this = this;
16411         var cmp = function(a,b) {   
16412             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16413         };
16414         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16415             throw "No top level modules to build";
16416         }
16417         
16418         // make a flat list in order of modules to build.
16419         var mods = this.topModule ? [ this.topModule ] : [];
16420                 
16421         
16422         // elmodules (is a list of DOM based modules )
16423         Roo.each(this.elmodules, function(e) {
16424             mods.push(e);
16425             if (!this.topModule &&
16426                 typeof(e.parent) == 'string' &&
16427                 e.parent.substring(0,1) == '#' &&
16428                 Roo.get(e.parent.substr(1))
16429                ) {
16430                 
16431                 _this.topModule = e;
16432             }
16433             
16434         });
16435
16436         
16437         // add modules to their parents..
16438         var addMod = function(m) {
16439             Roo.debug && Roo.log("build Order: add: " + m.name);
16440                 
16441             mods.push(m);
16442             if (m.modules && !m.disabled) {
16443                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16444                 m.modules.keySort('ASC',  cmp );
16445                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16446     
16447                 m.modules.each(addMod);
16448             } else {
16449                 Roo.debug && Roo.log("build Order: no child modules");
16450             }
16451             // not sure if this is used any more..
16452             if (m.finalize) {
16453                 m.finalize.name = m.name + " (clean up) ";
16454                 mods.push(m.finalize);
16455             }
16456             
16457         }
16458         if (this.topModule && this.topModule.modules) { 
16459             this.topModule.modules.keySort('ASC',  cmp );
16460             this.topModule.modules.each(addMod);
16461         } 
16462         return mods;
16463     },
16464     
16465      /**
16466      * Build the registered modules.
16467      * @param {Object} parent element.
16468      * @param {Function} optional method to call after module has been added.
16469      * 
16470      */ 
16471    
16472     build : function(opts) 
16473     {
16474         
16475         if (typeof(opts) != 'undefined') {
16476             Roo.apply(this,opts);
16477         }
16478         
16479         this.preBuild();
16480         var mods = this.buildOrder();
16481       
16482         //this.allmods = mods;
16483         //Roo.debug && Roo.log(mods);
16484         //return;
16485         if (!mods.length) { // should not happen
16486             throw "NO modules!!!";
16487         }
16488         
16489         
16490         var msg = "Building Interface...";
16491         // flash it up as modal - so we store the mask!?
16492         if (!this.hideProgress && Roo.MessageBox) {
16493             Roo.MessageBox.show({ title: 'loading' });
16494             Roo.MessageBox.show({
16495                title: "Please wait...",
16496                msg: msg,
16497                width:450,
16498                progress:true,
16499                closable:false,
16500                modal: false
16501               
16502             });
16503         }
16504         var total = mods.length;
16505         
16506         var _this = this;
16507         var progressRun = function() {
16508             if (!mods.length) {
16509                 Roo.debug && Roo.log('hide?');
16510                 if (!this.hideProgress && Roo.MessageBox) {
16511                     Roo.MessageBox.hide();
16512                 }
16513                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16514                 
16515                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16516                 
16517                 // THE END...
16518                 return false;   
16519             }
16520             
16521             var m = mods.shift();
16522             
16523             
16524             Roo.debug && Roo.log(m);
16525             // not sure if this is supported any more.. - modules that are are just function
16526             if (typeof(m) == 'function') { 
16527                 m.call(this);
16528                 return progressRun.defer(10, _this);
16529             } 
16530             
16531             
16532             msg = "Building Interface " + (total  - mods.length) + 
16533                     " of " + total + 
16534                     (m.name ? (' - ' + m.name) : '');
16535                         Roo.debug && Roo.log(msg);
16536             if (!_this.hideProgress &&  Roo.MessageBox) { 
16537                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16538             }
16539             
16540          
16541             // is the module disabled?
16542             var disabled = (typeof(m.disabled) == 'function') ?
16543                 m.disabled.call(m.module.disabled) : m.disabled;    
16544             
16545             
16546             if (disabled) {
16547                 return progressRun(); // we do not update the display!
16548             }
16549             
16550             // now build 
16551             
16552                         
16553                         
16554             m.render();
16555             // it's 10 on top level, and 1 on others??? why...
16556             return progressRun.defer(10, _this);
16557              
16558         }
16559         progressRun.defer(1, _this);
16560      
16561         
16562         
16563     },
16564         
16565         
16566         /**
16567          * Event Object.
16568          *
16569          *
16570          */
16571         event: false, 
16572     /**
16573          * wrapper for event.on - aliased later..  
16574          * Typically use to register a event handler for register:
16575          *
16576          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16577          *
16578          */
16579     on : false
16580    
16581     
16582     
16583 });
16584
16585 Roo.XComponent.event = new Roo.util.Observable({
16586                 events : { 
16587                         /**
16588                          * @event register
16589                          * Fires when an Component is registered,
16590                          * set the disable property on the Component to stop registration.
16591                          * @param {Roo.XComponent} c the component being registerd.
16592                          * 
16593                          */
16594                         'register' : true,
16595             /**
16596                          * @event beforebuild
16597                          * Fires before each Component is built
16598                          * can be used to apply permissions.
16599                          * @param {Roo.XComponent} c the component being registerd.
16600                          * 
16601                          */
16602                         'beforebuild' : true,
16603                         /**
16604                          * @event buildcomplete
16605                          * Fires on the top level element when all elements have been built
16606                          * @param {Roo.XComponent} the top level component.
16607                          */
16608                         'buildcomplete' : true
16609                         
16610                 }
16611 });
16612
16613 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16614  //
16615  /**
16616  * marked - a markdown parser
16617  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16618  * https://github.com/chjj/marked
16619  */
16620
16621
16622 /**
16623  *
16624  * Roo.Markdown - is a very crude wrapper around marked..
16625  *
16626  * usage:
16627  * 
16628  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16629  * 
16630  * Note: move the sample code to the bottom of this
16631  * file before uncommenting it.
16632  *
16633  */
16634
16635 Roo.Markdown = {};
16636 Roo.Markdown.toHtml = function(text) {
16637     
16638     var c = new Roo.Markdown.marked.setOptions({
16639             renderer: new Roo.Markdown.marked.Renderer(),
16640             gfm: true,
16641             tables: true,
16642             breaks: false,
16643             pedantic: false,
16644             sanitize: false,
16645             smartLists: true,
16646             smartypants: false
16647           });
16648     // A FEW HACKS!!?
16649     
16650     text = text.replace(/\\\n/g,' ');
16651     return Roo.Markdown.marked(text);
16652 };
16653 //
16654 // converter
16655 //
16656 // Wraps all "globals" so that the only thing
16657 // exposed is makeHtml().
16658 //
16659 (function() {
16660     
16661     /**
16662      * Block-Level Grammar
16663      */
16664     
16665     var block = {
16666       newline: /^\n+/,
16667       code: /^( {4}[^\n]+\n*)+/,
16668       fences: noop,
16669       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16670       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16671       nptable: noop,
16672       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16673       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16674       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16675       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16676       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16677       table: noop,
16678       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16679       text: /^[^\n]+/
16680     };
16681     
16682     block.bullet = /(?:[*+-]|\d+\.)/;
16683     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16684     block.item = replace(block.item, 'gm')
16685       (/bull/g, block.bullet)
16686       ();
16687     
16688     block.list = replace(block.list)
16689       (/bull/g, block.bullet)
16690       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16691       ('def', '\\n+(?=' + block.def.source + ')')
16692       ();
16693     
16694     block.blockquote = replace(block.blockquote)
16695       ('def', block.def)
16696       ();
16697     
16698     block._tag = '(?!(?:'
16699       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16700       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16701       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16702     
16703     block.html = replace(block.html)
16704       ('comment', /<!--[\s\S]*?-->/)
16705       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16706       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16707       (/tag/g, block._tag)
16708       ();
16709     
16710     block.paragraph = replace(block.paragraph)
16711       ('hr', block.hr)
16712       ('heading', block.heading)
16713       ('lheading', block.lheading)
16714       ('blockquote', block.blockquote)
16715       ('tag', '<' + block._tag)
16716       ('def', block.def)
16717       ();
16718     
16719     /**
16720      * Normal Block Grammar
16721      */
16722     
16723     block.normal = merge({}, block);
16724     
16725     /**
16726      * GFM Block Grammar
16727      */
16728     
16729     block.gfm = merge({}, block.normal, {
16730       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16731       paragraph: /^/,
16732       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16733     });
16734     
16735     block.gfm.paragraph = replace(block.paragraph)
16736       ('(?!', '(?!'
16737         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16738         + block.list.source.replace('\\1', '\\3') + '|')
16739       ();
16740     
16741     /**
16742      * GFM + Tables Block Grammar
16743      */
16744     
16745     block.tables = merge({}, block.gfm, {
16746       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16747       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16748     });
16749     
16750     /**
16751      * Block Lexer
16752      */
16753     
16754     function Lexer(options) {
16755       this.tokens = [];
16756       this.tokens.links = {};
16757       this.options = options || marked.defaults;
16758       this.rules = block.normal;
16759     
16760       if (this.options.gfm) {
16761         if (this.options.tables) {
16762           this.rules = block.tables;
16763         } else {
16764           this.rules = block.gfm;
16765         }
16766       }
16767     }
16768     
16769     /**
16770      * Expose Block Rules
16771      */
16772     
16773     Lexer.rules = block;
16774     
16775     /**
16776      * Static Lex Method
16777      */
16778     
16779     Lexer.lex = function(src, options) {
16780       var lexer = new Lexer(options);
16781       return lexer.lex(src);
16782     };
16783     
16784     /**
16785      * Preprocessing
16786      */
16787     
16788     Lexer.prototype.lex = function(src) {
16789       src = src
16790         .replace(/\r\n|\r/g, '\n')
16791         .replace(/\t/g, '    ')
16792         .replace(/\u00a0/g, ' ')
16793         .replace(/\u2424/g, '\n');
16794     
16795       return this.token(src, true);
16796     };
16797     
16798     /**
16799      * Lexing
16800      */
16801     
16802     Lexer.prototype.token = function(src, top, bq) {
16803       var src = src.replace(/^ +$/gm, '')
16804         , next
16805         , loose
16806         , cap
16807         , bull
16808         , b
16809         , item
16810         , space
16811         , i
16812         , l;
16813     
16814       while (src) {
16815         // newline
16816         if (cap = this.rules.newline.exec(src)) {
16817           src = src.substring(cap[0].length);
16818           if (cap[0].length > 1) {
16819             this.tokens.push({
16820               type: 'space'
16821             });
16822           }
16823         }
16824     
16825         // code
16826         if (cap = this.rules.code.exec(src)) {
16827           src = src.substring(cap[0].length);
16828           cap = cap[0].replace(/^ {4}/gm, '');
16829           this.tokens.push({
16830             type: 'code',
16831             text: !this.options.pedantic
16832               ? cap.replace(/\n+$/, '')
16833               : cap
16834           });
16835           continue;
16836         }
16837     
16838         // fences (gfm)
16839         if (cap = this.rules.fences.exec(src)) {
16840           src = src.substring(cap[0].length);
16841           this.tokens.push({
16842             type: 'code',
16843             lang: cap[2],
16844             text: cap[3] || ''
16845           });
16846           continue;
16847         }
16848     
16849         // heading
16850         if (cap = this.rules.heading.exec(src)) {
16851           src = src.substring(cap[0].length);
16852           this.tokens.push({
16853             type: 'heading',
16854             depth: cap[1].length,
16855             text: cap[2]
16856           });
16857           continue;
16858         }
16859     
16860         // table no leading pipe (gfm)
16861         if (top && (cap = this.rules.nptable.exec(src))) {
16862           src = src.substring(cap[0].length);
16863     
16864           item = {
16865             type: 'table',
16866             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16867             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16868             cells: cap[3].replace(/\n$/, '').split('\n')
16869           };
16870     
16871           for (i = 0; i < item.align.length; i++) {
16872             if (/^ *-+: *$/.test(item.align[i])) {
16873               item.align[i] = 'right';
16874             } else if (/^ *:-+: *$/.test(item.align[i])) {
16875               item.align[i] = 'center';
16876             } else if (/^ *:-+ *$/.test(item.align[i])) {
16877               item.align[i] = 'left';
16878             } else {
16879               item.align[i] = null;
16880             }
16881           }
16882     
16883           for (i = 0; i < item.cells.length; i++) {
16884             item.cells[i] = item.cells[i].split(/ *\| */);
16885           }
16886     
16887           this.tokens.push(item);
16888     
16889           continue;
16890         }
16891     
16892         // lheading
16893         if (cap = this.rules.lheading.exec(src)) {
16894           src = src.substring(cap[0].length);
16895           this.tokens.push({
16896             type: 'heading',
16897             depth: cap[2] === '=' ? 1 : 2,
16898             text: cap[1]
16899           });
16900           continue;
16901         }
16902     
16903         // hr
16904         if (cap = this.rules.hr.exec(src)) {
16905           src = src.substring(cap[0].length);
16906           this.tokens.push({
16907             type: 'hr'
16908           });
16909           continue;
16910         }
16911     
16912         // blockquote
16913         if (cap = this.rules.blockquote.exec(src)) {
16914           src = src.substring(cap[0].length);
16915     
16916           this.tokens.push({
16917             type: 'blockquote_start'
16918           });
16919     
16920           cap = cap[0].replace(/^ *> ?/gm, '');
16921     
16922           // Pass `top` to keep the current
16923           // "toplevel" state. This is exactly
16924           // how markdown.pl works.
16925           this.token(cap, top, true);
16926     
16927           this.tokens.push({
16928             type: 'blockquote_end'
16929           });
16930     
16931           continue;
16932         }
16933     
16934         // list
16935         if (cap = this.rules.list.exec(src)) {
16936           src = src.substring(cap[0].length);
16937           bull = cap[2];
16938     
16939           this.tokens.push({
16940             type: 'list_start',
16941             ordered: bull.length > 1
16942           });
16943     
16944           // Get each top-level item.
16945           cap = cap[0].match(this.rules.item);
16946     
16947           next = false;
16948           l = cap.length;
16949           i = 0;
16950     
16951           for (; i < l; i++) {
16952             item = cap[i];
16953     
16954             // Remove the list item's bullet
16955             // so it is seen as the next token.
16956             space = item.length;
16957             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16958     
16959             // Outdent whatever the
16960             // list item contains. Hacky.
16961             if (~item.indexOf('\n ')) {
16962               space -= item.length;
16963               item = !this.options.pedantic
16964                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16965                 : item.replace(/^ {1,4}/gm, '');
16966             }
16967     
16968             // Determine whether the next list item belongs here.
16969             // Backpedal if it does not belong in this list.
16970             if (this.options.smartLists && i !== l - 1) {
16971               b = block.bullet.exec(cap[i + 1])[0];
16972               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16973                 src = cap.slice(i + 1).join('\n') + src;
16974                 i = l - 1;
16975               }
16976             }
16977     
16978             // Determine whether item is loose or not.
16979             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16980             // for discount behavior.
16981             loose = next || /\n\n(?!\s*$)/.test(item);
16982             if (i !== l - 1) {
16983               next = item.charAt(item.length - 1) === '\n';
16984               if (!loose) { loose = next; }
16985             }
16986     
16987             this.tokens.push({
16988               type: loose
16989                 ? 'loose_item_start'
16990                 : 'list_item_start'
16991             });
16992     
16993             // Recurse.
16994             this.token(item, false, bq);
16995     
16996             this.tokens.push({
16997               type: 'list_item_end'
16998             });
16999           }
17000     
17001           this.tokens.push({
17002             type: 'list_end'
17003           });
17004     
17005           continue;
17006         }
17007     
17008         // html
17009         if (cap = this.rules.html.exec(src)) {
17010           src = src.substring(cap[0].length);
17011           this.tokens.push({
17012             type: this.options.sanitize
17013               ? 'paragraph'
17014               : 'html',
17015             pre: !this.options.sanitizer
17016               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17017             text: cap[0]
17018           });
17019           continue;
17020         }
17021     
17022         // def
17023         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17024           src = src.substring(cap[0].length);
17025           this.tokens.links[cap[1].toLowerCase()] = {
17026             href: cap[2],
17027             title: cap[3]
17028           };
17029           continue;
17030         }
17031     
17032         // table (gfm)
17033         if (top && (cap = this.rules.table.exec(src))) {
17034           src = src.substring(cap[0].length);
17035     
17036           item = {
17037             type: 'table',
17038             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17039             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17040             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17041           };
17042     
17043           for (i = 0; i < item.align.length; i++) {
17044             if (/^ *-+: *$/.test(item.align[i])) {
17045               item.align[i] = 'right';
17046             } else if (/^ *:-+: *$/.test(item.align[i])) {
17047               item.align[i] = 'center';
17048             } else if (/^ *:-+ *$/.test(item.align[i])) {
17049               item.align[i] = 'left';
17050             } else {
17051               item.align[i] = null;
17052             }
17053           }
17054     
17055           for (i = 0; i < item.cells.length; i++) {
17056             item.cells[i] = item.cells[i]
17057               .replace(/^ *\| *| *\| *$/g, '')
17058               .split(/ *\| */);
17059           }
17060     
17061           this.tokens.push(item);
17062     
17063           continue;
17064         }
17065     
17066         // top-level paragraph
17067         if (top && (cap = this.rules.paragraph.exec(src))) {
17068           src = src.substring(cap[0].length);
17069           this.tokens.push({
17070             type: 'paragraph',
17071             text: cap[1].charAt(cap[1].length - 1) === '\n'
17072               ? cap[1].slice(0, -1)
17073               : cap[1]
17074           });
17075           continue;
17076         }
17077     
17078         // text
17079         if (cap = this.rules.text.exec(src)) {
17080           // Top-level should never reach here.
17081           src = src.substring(cap[0].length);
17082           this.tokens.push({
17083             type: 'text',
17084             text: cap[0]
17085           });
17086           continue;
17087         }
17088     
17089         if (src) {
17090           throw new
17091             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17092         }
17093       }
17094     
17095       return this.tokens;
17096     };
17097     
17098     /**
17099      * Inline-Level Grammar
17100      */
17101     
17102     var inline = {
17103       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17104       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17105       url: noop,
17106       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17107       link: /^!?\[(inside)\]\(href\)/,
17108       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17109       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17110       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17111       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17112       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17113       br: /^ {2,}\n(?!\s*$)/,
17114       del: noop,
17115       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17116     };
17117     
17118     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17119     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17120     
17121     inline.link = replace(inline.link)
17122       ('inside', inline._inside)
17123       ('href', inline._href)
17124       ();
17125     
17126     inline.reflink = replace(inline.reflink)
17127       ('inside', inline._inside)
17128       ();
17129     
17130     /**
17131      * Normal Inline Grammar
17132      */
17133     
17134     inline.normal = merge({}, inline);
17135     
17136     /**
17137      * Pedantic Inline Grammar
17138      */
17139     
17140     inline.pedantic = merge({}, inline.normal, {
17141       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17142       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17143     });
17144     
17145     /**
17146      * GFM Inline Grammar
17147      */
17148     
17149     inline.gfm = merge({}, inline.normal, {
17150       escape: replace(inline.escape)('])', '~|])')(),
17151       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17152       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17153       text: replace(inline.text)
17154         (']|', '~]|')
17155         ('|', '|https?://|')
17156         ()
17157     });
17158     
17159     /**
17160      * GFM + Line Breaks Inline Grammar
17161      */
17162     
17163     inline.breaks = merge({}, inline.gfm, {
17164       br: replace(inline.br)('{2,}', '*')(),
17165       text: replace(inline.gfm.text)('{2,}', '*')()
17166     });
17167     
17168     /**
17169      * Inline Lexer & Compiler
17170      */
17171     
17172     function InlineLexer(links, options) {
17173       this.options = options || marked.defaults;
17174       this.links = links;
17175       this.rules = inline.normal;
17176       this.renderer = this.options.renderer || new Renderer;
17177       this.renderer.options = this.options;
17178     
17179       if (!this.links) {
17180         throw new
17181           Error('Tokens array requires a `links` property.');
17182       }
17183     
17184       if (this.options.gfm) {
17185         if (this.options.breaks) {
17186           this.rules = inline.breaks;
17187         } else {
17188           this.rules = inline.gfm;
17189         }
17190       } else if (this.options.pedantic) {
17191         this.rules = inline.pedantic;
17192       }
17193     }
17194     
17195     /**
17196      * Expose Inline Rules
17197      */
17198     
17199     InlineLexer.rules = inline;
17200     
17201     /**
17202      * Static Lexing/Compiling Method
17203      */
17204     
17205     InlineLexer.output = function(src, links, options) {
17206       var inline = new InlineLexer(links, options);
17207       return inline.output(src);
17208     };
17209     
17210     /**
17211      * Lexing/Compiling
17212      */
17213     
17214     InlineLexer.prototype.output = function(src) {
17215       var out = ''
17216         , link
17217         , text
17218         , href
17219         , cap;
17220     
17221       while (src) {
17222         // escape
17223         if (cap = this.rules.escape.exec(src)) {
17224           src = src.substring(cap[0].length);
17225           out += cap[1];
17226           continue;
17227         }
17228     
17229         // autolink
17230         if (cap = this.rules.autolink.exec(src)) {
17231           src = src.substring(cap[0].length);
17232           if (cap[2] === '@') {
17233             text = cap[1].charAt(6) === ':'
17234               ? this.mangle(cap[1].substring(7))
17235               : this.mangle(cap[1]);
17236             href = this.mangle('mailto:') + text;
17237           } else {
17238             text = escape(cap[1]);
17239             href = text;
17240           }
17241           out += this.renderer.link(href, null, text);
17242           continue;
17243         }
17244     
17245         // url (gfm)
17246         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17247           src = src.substring(cap[0].length);
17248           text = escape(cap[1]);
17249           href = text;
17250           out += this.renderer.link(href, null, text);
17251           continue;
17252         }
17253     
17254         // tag
17255         if (cap = this.rules.tag.exec(src)) {
17256           if (!this.inLink && /^<a /i.test(cap[0])) {
17257             this.inLink = true;
17258           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17259             this.inLink = false;
17260           }
17261           src = src.substring(cap[0].length);
17262           out += this.options.sanitize
17263             ? this.options.sanitizer
17264               ? this.options.sanitizer(cap[0])
17265               : escape(cap[0])
17266             : cap[0];
17267           continue;
17268         }
17269     
17270         // link
17271         if (cap = this.rules.link.exec(src)) {
17272           src = src.substring(cap[0].length);
17273           this.inLink = true;
17274           out += this.outputLink(cap, {
17275             href: cap[2],
17276             title: cap[3]
17277           });
17278           this.inLink = false;
17279           continue;
17280         }
17281     
17282         // reflink, nolink
17283         if ((cap = this.rules.reflink.exec(src))
17284             || (cap = this.rules.nolink.exec(src))) {
17285           src = src.substring(cap[0].length);
17286           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17287           link = this.links[link.toLowerCase()];
17288           if (!link || !link.href) {
17289             out += cap[0].charAt(0);
17290             src = cap[0].substring(1) + src;
17291             continue;
17292           }
17293           this.inLink = true;
17294           out += this.outputLink(cap, link);
17295           this.inLink = false;
17296           continue;
17297         }
17298     
17299         // strong
17300         if (cap = this.rules.strong.exec(src)) {
17301           src = src.substring(cap[0].length);
17302           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17303           continue;
17304         }
17305     
17306         // em
17307         if (cap = this.rules.em.exec(src)) {
17308           src = src.substring(cap[0].length);
17309           out += this.renderer.em(this.output(cap[2] || cap[1]));
17310           continue;
17311         }
17312     
17313         // code
17314         if (cap = this.rules.code.exec(src)) {
17315           src = src.substring(cap[0].length);
17316           out += this.renderer.codespan(escape(cap[2], true));
17317           continue;
17318         }
17319     
17320         // br
17321         if (cap = this.rules.br.exec(src)) {
17322           src = src.substring(cap[0].length);
17323           out += this.renderer.br();
17324           continue;
17325         }
17326     
17327         // del (gfm)
17328         if (cap = this.rules.del.exec(src)) {
17329           src = src.substring(cap[0].length);
17330           out += this.renderer.del(this.output(cap[1]));
17331           continue;
17332         }
17333     
17334         // text
17335         if (cap = this.rules.text.exec(src)) {
17336           src = src.substring(cap[0].length);
17337           out += this.renderer.text(escape(this.smartypants(cap[0])));
17338           continue;
17339         }
17340     
17341         if (src) {
17342           throw new
17343             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17344         }
17345       }
17346     
17347       return out;
17348     };
17349     
17350     /**
17351      * Compile Link
17352      */
17353     
17354     InlineLexer.prototype.outputLink = function(cap, link) {
17355       var href = escape(link.href)
17356         , title = link.title ? escape(link.title) : null;
17357     
17358       return cap[0].charAt(0) !== '!'
17359         ? this.renderer.link(href, title, this.output(cap[1]))
17360         : this.renderer.image(href, title, escape(cap[1]));
17361     };
17362     
17363     /**
17364      * Smartypants Transformations
17365      */
17366     
17367     InlineLexer.prototype.smartypants = function(text) {
17368       if (!this.options.smartypants)  { return text; }
17369       return text
17370         // em-dashes
17371         .replace(/---/g, '\u2014')
17372         // en-dashes
17373         .replace(/--/g, '\u2013')
17374         // opening singles
17375         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17376         // closing singles & apostrophes
17377         .replace(/'/g, '\u2019')
17378         // opening doubles
17379         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17380         // closing doubles
17381         .replace(/"/g, '\u201d')
17382         // ellipses
17383         .replace(/\.{3}/g, '\u2026');
17384     };
17385     
17386     /**
17387      * Mangle Links
17388      */
17389     
17390     InlineLexer.prototype.mangle = function(text) {
17391       if (!this.options.mangle) { return text; }
17392       var out = ''
17393         , l = text.length
17394         , i = 0
17395         , ch;
17396     
17397       for (; i < l; i++) {
17398         ch = text.charCodeAt(i);
17399         if (Math.random() > 0.5) {
17400           ch = 'x' + ch.toString(16);
17401         }
17402         out += '&#' + ch + ';';
17403       }
17404     
17405       return out;
17406     };
17407     
17408     /**
17409      * Renderer
17410      */
17411     
17412     function Renderer(options) {
17413       this.options = options || {};
17414     }
17415     
17416     Renderer.prototype.code = function(code, lang, escaped) {
17417       if (this.options.highlight) {
17418         var out = this.options.highlight(code, lang);
17419         if (out != null && out !== code) {
17420           escaped = true;
17421           code = out;
17422         }
17423       } else {
17424             // hack!!! - it's already escapeD?
17425             escaped = true;
17426       }
17427     
17428       if (!lang) {
17429         return '<pre><code>'
17430           + (escaped ? code : escape(code, true))
17431           + '\n</code></pre>';
17432       }
17433     
17434       return '<pre><code class="'
17435         + this.options.langPrefix
17436         + escape(lang, true)
17437         + '">'
17438         + (escaped ? code : escape(code, true))
17439         + '\n</code></pre>\n';
17440     };
17441     
17442     Renderer.prototype.blockquote = function(quote) {
17443       return '<blockquote>\n' + quote + '</blockquote>\n';
17444     };
17445     
17446     Renderer.prototype.html = function(html) {
17447       return html;
17448     };
17449     
17450     Renderer.prototype.heading = function(text, level, raw) {
17451       return '<h'
17452         + level
17453         + ' id="'
17454         + this.options.headerPrefix
17455         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17456         + '">'
17457         + text
17458         + '</h'
17459         + level
17460         + '>\n';
17461     };
17462     
17463     Renderer.prototype.hr = function() {
17464       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17465     };
17466     
17467     Renderer.prototype.list = function(body, ordered) {
17468       var type = ordered ? 'ol' : 'ul';
17469       return '<' + type + '>\n' + body + '</' + type + '>\n';
17470     };
17471     
17472     Renderer.prototype.listitem = function(text) {
17473       return '<li>' + text + '</li>\n';
17474     };
17475     
17476     Renderer.prototype.paragraph = function(text) {
17477       return '<p>' + text + '</p>\n';
17478     };
17479     
17480     Renderer.prototype.table = function(header, body) {
17481       return '<table class="table table-striped">\n'
17482         + '<thead>\n'
17483         + header
17484         + '</thead>\n'
17485         + '<tbody>\n'
17486         + body
17487         + '</tbody>\n'
17488         + '</table>\n';
17489     };
17490     
17491     Renderer.prototype.tablerow = function(content) {
17492       return '<tr>\n' + content + '</tr>\n';
17493     };
17494     
17495     Renderer.prototype.tablecell = function(content, flags) {
17496       var type = flags.header ? 'th' : 'td';
17497       var tag = flags.align
17498         ? '<' + type + ' style="text-align:' + flags.align + '">'
17499         : '<' + type + '>';
17500       return tag + content + '</' + type + '>\n';
17501     };
17502     
17503     // span level renderer
17504     Renderer.prototype.strong = function(text) {
17505       return '<strong>' + text + '</strong>';
17506     };
17507     
17508     Renderer.prototype.em = function(text) {
17509       return '<em>' + text + '</em>';
17510     };
17511     
17512     Renderer.prototype.codespan = function(text) {
17513       return '<code>' + text + '</code>';
17514     };
17515     
17516     Renderer.prototype.br = function() {
17517       return this.options.xhtml ? '<br/>' : '<br>';
17518     };
17519     
17520     Renderer.prototype.del = function(text) {
17521       return '<del>' + text + '</del>';
17522     };
17523     
17524     Renderer.prototype.link = function(href, title, text) {
17525       if (this.options.sanitize) {
17526         try {
17527           var prot = decodeURIComponent(unescape(href))
17528             .replace(/[^\w:]/g, '')
17529             .toLowerCase();
17530         } catch (e) {
17531           return '';
17532         }
17533         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17534           return '';
17535         }
17536       }
17537       var out = '<a href="' + href + '"';
17538       if (title) {
17539         out += ' title="' + title + '"';
17540       }
17541       out += '>' + text + '</a>';
17542       return out;
17543     };
17544     
17545     Renderer.prototype.image = function(href, title, text) {
17546       var out = '<img src="' + href + '" alt="' + text + '"';
17547       if (title) {
17548         out += ' title="' + title + '"';
17549       }
17550       out += this.options.xhtml ? '/>' : '>';
17551       return out;
17552     };
17553     
17554     Renderer.prototype.text = function(text) {
17555       return text;
17556     };
17557     
17558     /**
17559      * Parsing & Compiling
17560      */
17561     
17562     function Parser(options) {
17563       this.tokens = [];
17564       this.token = null;
17565       this.options = options || marked.defaults;
17566       this.options.renderer = this.options.renderer || new Renderer;
17567       this.renderer = this.options.renderer;
17568       this.renderer.options = this.options;
17569     }
17570     
17571     /**
17572      * Static Parse Method
17573      */
17574     
17575     Parser.parse = function(src, options, renderer) {
17576       var parser = new Parser(options, renderer);
17577       return parser.parse(src);
17578     };
17579     
17580     /**
17581      * Parse Loop
17582      */
17583     
17584     Parser.prototype.parse = function(src) {
17585       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17586       this.tokens = src.reverse();
17587     
17588       var out = '';
17589       while (this.next()) {
17590         out += this.tok();
17591       }
17592     
17593       return out;
17594     };
17595     
17596     /**
17597      * Next Token
17598      */
17599     
17600     Parser.prototype.next = function() {
17601       return this.token = this.tokens.pop();
17602     };
17603     
17604     /**
17605      * Preview Next Token
17606      */
17607     
17608     Parser.prototype.peek = function() {
17609       return this.tokens[this.tokens.length - 1] || 0;
17610     };
17611     
17612     /**
17613      * Parse Text Tokens
17614      */
17615     
17616     Parser.prototype.parseText = function() {
17617       var body = this.token.text;
17618     
17619       while (this.peek().type === 'text') {
17620         body += '\n' + this.next().text;
17621       }
17622     
17623       return this.inline.output(body);
17624     };
17625     
17626     /**
17627      * Parse Current Token
17628      */
17629     
17630     Parser.prototype.tok = function() {
17631       switch (this.token.type) {
17632         case 'space': {
17633           return '';
17634         }
17635         case 'hr': {
17636           return this.renderer.hr();
17637         }
17638         case 'heading': {
17639           return this.renderer.heading(
17640             this.inline.output(this.token.text),
17641             this.token.depth,
17642             this.token.text);
17643         }
17644         case 'code': {
17645           return this.renderer.code(this.token.text,
17646             this.token.lang,
17647             this.token.escaped);
17648         }
17649         case 'table': {
17650           var header = ''
17651             , body = ''
17652             , i
17653             , row
17654             , cell
17655             , flags
17656             , j;
17657     
17658           // header
17659           cell = '';
17660           for (i = 0; i < this.token.header.length; i++) {
17661             flags = { header: true, align: this.token.align[i] };
17662             cell += this.renderer.tablecell(
17663               this.inline.output(this.token.header[i]),
17664               { header: true, align: this.token.align[i] }
17665             );
17666           }
17667           header += this.renderer.tablerow(cell);
17668     
17669           for (i = 0; i < this.token.cells.length; i++) {
17670             row = this.token.cells[i];
17671     
17672             cell = '';
17673             for (j = 0; j < row.length; j++) {
17674               cell += this.renderer.tablecell(
17675                 this.inline.output(row[j]),
17676                 { header: false, align: this.token.align[j] }
17677               );
17678             }
17679     
17680             body += this.renderer.tablerow(cell);
17681           }
17682           return this.renderer.table(header, body);
17683         }
17684         case 'blockquote_start': {
17685           var body = '';
17686     
17687           while (this.next().type !== 'blockquote_end') {
17688             body += this.tok();
17689           }
17690     
17691           return this.renderer.blockquote(body);
17692         }
17693         case 'list_start': {
17694           var body = ''
17695             , ordered = this.token.ordered;
17696     
17697           while (this.next().type !== 'list_end') {
17698             body += this.tok();
17699           }
17700     
17701           return this.renderer.list(body, ordered);
17702         }
17703         case 'list_item_start': {
17704           var body = '';
17705     
17706           while (this.next().type !== 'list_item_end') {
17707             body += this.token.type === 'text'
17708               ? this.parseText()
17709               : this.tok();
17710           }
17711     
17712           return this.renderer.listitem(body);
17713         }
17714         case 'loose_item_start': {
17715           var body = '';
17716     
17717           while (this.next().type !== 'list_item_end') {
17718             body += this.tok();
17719           }
17720     
17721           return this.renderer.listitem(body);
17722         }
17723         case 'html': {
17724           var html = !this.token.pre && !this.options.pedantic
17725             ? this.inline.output(this.token.text)
17726             : this.token.text;
17727           return this.renderer.html(html);
17728         }
17729         case 'paragraph': {
17730           return this.renderer.paragraph(this.inline.output(this.token.text));
17731         }
17732         case 'text': {
17733           return this.renderer.paragraph(this.parseText());
17734         }
17735       }
17736     };
17737     
17738     /**
17739      * Helpers
17740      */
17741     
17742     function escape(html, encode) {
17743       return html
17744         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17745         .replace(/</g, '&lt;')
17746         .replace(/>/g, '&gt;')
17747         .replace(/"/g, '&quot;')
17748         .replace(/'/g, '&#39;');
17749     }
17750     
17751     function unescape(html) {
17752         // explicitly match decimal, hex, and named HTML entities 
17753       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17754         n = n.toLowerCase();
17755         if (n === 'colon') { return ':'; }
17756         if (n.charAt(0) === '#') {
17757           return n.charAt(1) === 'x'
17758             ? String.fromCharCode(parseInt(n.substring(2), 16))
17759             : String.fromCharCode(+n.substring(1));
17760         }
17761         return '';
17762       });
17763     }
17764     
17765     function replace(regex, opt) {
17766       regex = regex.source;
17767       opt = opt || '';
17768       return function self(name, val) {
17769         if (!name) { return new RegExp(regex, opt); }
17770         val = val.source || val;
17771         val = val.replace(/(^|[^\[])\^/g, '$1');
17772         regex = regex.replace(name, val);
17773         return self;
17774       };
17775     }
17776     
17777     function noop() {}
17778     noop.exec = noop;
17779     
17780     function merge(obj) {
17781       var i = 1
17782         , target
17783         , key;
17784     
17785       for (; i < arguments.length; i++) {
17786         target = arguments[i];
17787         for (key in target) {
17788           if (Object.prototype.hasOwnProperty.call(target, key)) {
17789             obj[key] = target[key];
17790           }
17791         }
17792       }
17793     
17794       return obj;
17795     }
17796     
17797     
17798     /**
17799      * Marked
17800      */
17801     
17802     function marked(src, opt, callback) {
17803       if (callback || typeof opt === 'function') {
17804         if (!callback) {
17805           callback = opt;
17806           opt = null;
17807         }
17808     
17809         opt = merge({}, marked.defaults, opt || {});
17810     
17811         var highlight = opt.highlight
17812           , tokens
17813           , pending
17814           , i = 0;
17815     
17816         try {
17817           tokens = Lexer.lex(src, opt)
17818         } catch (e) {
17819           return callback(e);
17820         }
17821     
17822         pending = tokens.length;
17823     
17824         var done = function(err) {
17825           if (err) {
17826             opt.highlight = highlight;
17827             return callback(err);
17828           }
17829     
17830           var out;
17831     
17832           try {
17833             out = Parser.parse(tokens, opt);
17834           } catch (e) {
17835             err = e;
17836           }
17837     
17838           opt.highlight = highlight;
17839     
17840           return err
17841             ? callback(err)
17842             : callback(null, out);
17843         };
17844     
17845         if (!highlight || highlight.length < 3) {
17846           return done();
17847         }
17848     
17849         delete opt.highlight;
17850     
17851         if (!pending) { return done(); }
17852     
17853         for (; i < tokens.length; i++) {
17854           (function(token) {
17855             if (token.type !== 'code') {
17856               return --pending || done();
17857             }
17858             return highlight(token.text, token.lang, function(err, code) {
17859               if (err) { return done(err); }
17860               if (code == null || code === token.text) {
17861                 return --pending || done();
17862               }
17863               token.text = code;
17864               token.escaped = true;
17865               --pending || done();
17866             });
17867           })(tokens[i]);
17868         }
17869     
17870         return;
17871       }
17872       try {
17873         if (opt) { opt = merge({}, marked.defaults, opt); }
17874         return Parser.parse(Lexer.lex(src, opt), opt);
17875       } catch (e) {
17876         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17877         if ((opt || marked.defaults).silent) {
17878           return '<p>An error occured:</p><pre>'
17879             + escape(e.message + '', true)
17880             + '</pre>';
17881         }
17882         throw e;
17883       }
17884     }
17885     
17886     /**
17887      * Options
17888      */
17889     
17890     marked.options =
17891     marked.setOptions = function(opt) {
17892       merge(marked.defaults, opt);
17893       return marked;
17894     };
17895     
17896     marked.defaults = {
17897       gfm: true,
17898       tables: true,
17899       breaks: false,
17900       pedantic: false,
17901       sanitize: false,
17902       sanitizer: null,
17903       mangle: true,
17904       smartLists: false,
17905       silent: false,
17906       highlight: null,
17907       langPrefix: 'lang-',
17908       smartypants: false,
17909       headerPrefix: '',
17910       renderer: new Renderer,
17911       xhtml: false
17912     };
17913     
17914     /**
17915      * Expose
17916      */
17917     
17918     marked.Parser = Parser;
17919     marked.parser = Parser.parse;
17920     
17921     marked.Renderer = Renderer;
17922     
17923     marked.Lexer = Lexer;
17924     marked.lexer = Lexer.lex;
17925     
17926     marked.InlineLexer = InlineLexer;
17927     marked.inlineLexer = InlineLexer.output;
17928     
17929     marked.parse = marked;
17930     
17931     Roo.Markdown.marked = marked;
17932
17933 })();/*
17934  * Based on:
17935  * Ext JS Library 1.1.1
17936  * Copyright(c) 2006-2007, Ext JS, LLC.
17937  *
17938  * Originally Released Under LGPL - original licence link has changed is not relivant.
17939  *
17940  * Fork - LGPL
17941  * <script type="text/javascript">
17942  */
17943
17944
17945
17946 /*
17947  * These classes are derivatives of the similarly named classes in the YUI Library.
17948  * The original license:
17949  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17950  * Code licensed under the BSD License:
17951  * http://developer.yahoo.net/yui/license.txt
17952  */
17953
17954 (function() {
17955
17956 var Event=Roo.EventManager;
17957 var Dom=Roo.lib.Dom;
17958
17959 /**
17960  * @class Roo.dd.DragDrop
17961  * @extends Roo.util.Observable
17962  * Defines the interface and base operation of items that that can be
17963  * dragged or can be drop targets.  It was designed to be extended, overriding
17964  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17965  * Up to three html elements can be associated with a DragDrop instance:
17966  * <ul>
17967  * <li>linked element: the element that is passed into the constructor.
17968  * This is the element which defines the boundaries for interaction with
17969  * other DragDrop objects.</li>
17970  * <li>handle element(s): The drag operation only occurs if the element that
17971  * was clicked matches a handle element.  By default this is the linked
17972  * element, but there are times that you will want only a portion of the
17973  * linked element to initiate the drag operation, and the setHandleElId()
17974  * method provides a way to define this.</li>
17975  * <li>drag element: this represents the element that would be moved along
17976  * with the cursor during a drag operation.  By default, this is the linked
17977  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17978  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17979  * </li>
17980  * </ul>
17981  * This class should not be instantiated until the onload event to ensure that
17982  * the associated elements are available.
17983  * The following would define a DragDrop obj that would interact with any
17984  * other DragDrop obj in the "group1" group:
17985  * <pre>
17986  *  dd = new Roo.dd.DragDrop("div1", "group1");
17987  * </pre>
17988  * Since none of the event handlers have been implemented, nothing would
17989  * actually happen if you were to run the code above.  Normally you would
17990  * override this class or one of the default implementations, but you can
17991  * also override the methods you want on an instance of the class...
17992  * <pre>
17993  *  dd.onDragDrop = function(e, id) {
17994  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
17995  *  }
17996  * </pre>
17997  * @constructor
17998  * @param {String} id of the element that is linked to this instance
17999  * @param {String} sGroup the group of related DragDrop objects
18000  * @param {object} config an object containing configurable attributes
18001  *                Valid properties for DragDrop:
18002  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18003  */
18004 Roo.dd.DragDrop = function(id, sGroup, config) {
18005     if (id) {
18006         this.init(id, sGroup, config);
18007     }
18008     
18009 };
18010
18011 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18012
18013     /**
18014      * The id of the element associated with this object.  This is what we
18015      * refer to as the "linked element" because the size and position of
18016      * this element is used to determine when the drag and drop objects have
18017      * interacted.
18018      * @property id
18019      * @type String
18020      */
18021     id: null,
18022
18023     /**
18024      * Configuration attributes passed into the constructor
18025      * @property config
18026      * @type object
18027      */
18028     config: null,
18029
18030     /**
18031      * The id of the element that will be dragged.  By default this is same
18032      * as the linked element , but could be changed to another element. Ex:
18033      * Roo.dd.DDProxy
18034      * @property dragElId
18035      * @type String
18036      * @private
18037      */
18038     dragElId: null,
18039
18040     /**
18041      * the id of the element that initiates the drag operation.  By default
18042      * this is the linked element, but could be changed to be a child of this
18043      * element.  This lets us do things like only starting the drag when the
18044      * header element within the linked html element is clicked.
18045      * @property handleElId
18046      * @type String
18047      * @private
18048      */
18049     handleElId: null,
18050
18051     /**
18052      * An associative array of HTML tags that will be ignored if clicked.
18053      * @property invalidHandleTypes
18054      * @type {string: string}
18055      */
18056     invalidHandleTypes: null,
18057
18058     /**
18059      * An associative array of ids for elements that will be ignored if clicked
18060      * @property invalidHandleIds
18061      * @type {string: string}
18062      */
18063     invalidHandleIds: null,
18064
18065     /**
18066      * An indexted array of css class names for elements that will be ignored
18067      * if clicked.
18068      * @property invalidHandleClasses
18069      * @type string[]
18070      */
18071     invalidHandleClasses: null,
18072
18073     /**
18074      * The linked element's absolute X position at the time the drag was
18075      * started
18076      * @property startPageX
18077      * @type int
18078      * @private
18079      */
18080     startPageX: 0,
18081
18082     /**
18083      * The linked element's absolute X position at the time the drag was
18084      * started
18085      * @property startPageY
18086      * @type int
18087      * @private
18088      */
18089     startPageY: 0,
18090
18091     /**
18092      * The group defines a logical collection of DragDrop objects that are
18093      * related.  Instances only get events when interacting with other
18094      * DragDrop object in the same group.  This lets us define multiple
18095      * groups using a single DragDrop subclass if we want.
18096      * @property groups
18097      * @type {string: string}
18098      */
18099     groups: null,
18100
18101     /**
18102      * Individual drag/drop instances can be locked.  This will prevent
18103      * onmousedown start drag.
18104      * @property locked
18105      * @type boolean
18106      * @private
18107      */
18108     locked: false,
18109
18110     /**
18111      * Lock this instance
18112      * @method lock
18113      */
18114     lock: function() { this.locked = true; },
18115
18116     /**
18117      * Unlock this instace
18118      * @method unlock
18119      */
18120     unlock: function() { this.locked = false; },
18121
18122     /**
18123      * By default, all insances can be a drop target.  This can be disabled by
18124      * setting isTarget to false.
18125      * @method isTarget
18126      * @type boolean
18127      */
18128     isTarget: true,
18129
18130     /**
18131      * The padding configured for this drag and drop object for calculating
18132      * the drop zone intersection with this object.
18133      * @method padding
18134      * @type int[]
18135      */
18136     padding: null,
18137
18138     /**
18139      * Cached reference to the linked element
18140      * @property _domRef
18141      * @private
18142      */
18143     _domRef: null,
18144
18145     /**
18146      * Internal typeof flag
18147      * @property __ygDragDrop
18148      * @private
18149      */
18150     __ygDragDrop: true,
18151
18152     /**
18153      * Set to true when horizontal contraints are applied
18154      * @property constrainX
18155      * @type boolean
18156      * @private
18157      */
18158     constrainX: false,
18159
18160     /**
18161      * Set to true when vertical contraints are applied
18162      * @property constrainY
18163      * @type boolean
18164      * @private
18165      */
18166     constrainY: false,
18167
18168     /**
18169      * The left constraint
18170      * @property minX
18171      * @type int
18172      * @private
18173      */
18174     minX: 0,
18175
18176     /**
18177      * The right constraint
18178      * @property maxX
18179      * @type int
18180      * @private
18181      */
18182     maxX: 0,
18183
18184     /**
18185      * The up constraint
18186      * @property minY
18187      * @type int
18188      * @type int
18189      * @private
18190      */
18191     minY: 0,
18192
18193     /**
18194      * The down constraint
18195      * @property maxY
18196      * @type int
18197      * @private
18198      */
18199     maxY: 0,
18200
18201     /**
18202      * Maintain offsets when we resetconstraints.  Set to true when you want
18203      * the position of the element relative to its parent to stay the same
18204      * when the page changes
18205      *
18206      * @property maintainOffset
18207      * @type boolean
18208      */
18209     maintainOffset: false,
18210
18211     /**
18212      * Array of pixel locations the element will snap to if we specified a
18213      * horizontal graduation/interval.  This array is generated automatically
18214      * when you define a tick interval.
18215      * @property xTicks
18216      * @type int[]
18217      */
18218     xTicks: null,
18219
18220     /**
18221      * Array of pixel locations the element will snap to if we specified a
18222      * vertical graduation/interval.  This array is generated automatically
18223      * when you define a tick interval.
18224      * @property yTicks
18225      * @type int[]
18226      */
18227     yTicks: null,
18228
18229     /**
18230      * By default the drag and drop instance will only respond to the primary
18231      * button click (left button for a right-handed mouse).  Set to true to
18232      * allow drag and drop to start with any mouse click that is propogated
18233      * by the browser
18234      * @property primaryButtonOnly
18235      * @type boolean
18236      */
18237     primaryButtonOnly: true,
18238
18239     /**
18240      * The availabe property is false until the linked dom element is accessible.
18241      * @property available
18242      * @type boolean
18243      */
18244     available: false,
18245
18246     /**
18247      * By default, drags can only be initiated if the mousedown occurs in the
18248      * region the linked element is.  This is done in part to work around a
18249      * bug in some browsers that mis-report the mousedown if the previous
18250      * mouseup happened outside of the window.  This property is set to true
18251      * if outer handles are defined.
18252      *
18253      * @property hasOuterHandles
18254      * @type boolean
18255      * @default false
18256      */
18257     hasOuterHandles: false,
18258
18259     /**
18260      * Code that executes immediately before the startDrag event
18261      * @method b4StartDrag
18262      * @private
18263      */
18264     b4StartDrag: function(x, y) { },
18265
18266     /**
18267      * Abstract method called after a drag/drop object is clicked
18268      * and the drag or mousedown time thresholds have beeen met.
18269      * @method startDrag
18270      * @param {int} X click location
18271      * @param {int} Y click location
18272      */
18273     startDrag: function(x, y) { /* override this */ },
18274
18275     /**
18276      * Code that executes immediately before the onDrag event
18277      * @method b4Drag
18278      * @private
18279      */
18280     b4Drag: function(e) { },
18281
18282     /**
18283      * Abstract method called during the onMouseMove event while dragging an
18284      * object.
18285      * @method onDrag
18286      * @param {Event} e the mousemove event
18287      */
18288     onDrag: function(e) { /* override this */ },
18289
18290     /**
18291      * Abstract method called when this element fist begins hovering over
18292      * another DragDrop obj
18293      * @method onDragEnter
18294      * @param {Event} e the mousemove event
18295      * @param {String|DragDrop[]} id In POINT mode, the element
18296      * id this is hovering over.  In INTERSECT mode, an array of one or more
18297      * dragdrop items being hovered over.
18298      */
18299     onDragEnter: function(e, id) { /* override this */ },
18300
18301     /**
18302      * Code that executes immediately before the onDragOver event
18303      * @method b4DragOver
18304      * @private
18305      */
18306     b4DragOver: function(e) { },
18307
18308     /**
18309      * Abstract method called when this element is hovering over another
18310      * DragDrop obj
18311      * @method onDragOver
18312      * @param {Event} e the mousemove event
18313      * @param {String|DragDrop[]} id In POINT mode, the element
18314      * id this is hovering over.  In INTERSECT mode, an array of dd items
18315      * being hovered over.
18316      */
18317     onDragOver: function(e, id) { /* override this */ },
18318
18319     /**
18320      * Code that executes immediately before the onDragOut event
18321      * @method b4DragOut
18322      * @private
18323      */
18324     b4DragOut: function(e) { },
18325
18326     /**
18327      * Abstract method called when we are no longer hovering over an element
18328      * @method onDragOut
18329      * @param {Event} e the mousemove event
18330      * @param {String|DragDrop[]} id In POINT mode, the element
18331      * id this was hovering over.  In INTERSECT mode, an array of dd items
18332      * that the mouse is no longer over.
18333      */
18334     onDragOut: function(e, id) { /* override this */ },
18335
18336     /**
18337      * Code that executes immediately before the onDragDrop event
18338      * @method b4DragDrop
18339      * @private
18340      */
18341     b4DragDrop: function(e) { },
18342
18343     /**
18344      * Abstract method called when this item is dropped on another DragDrop
18345      * obj
18346      * @method onDragDrop
18347      * @param {Event} e the mouseup event
18348      * @param {String|DragDrop[]} id In POINT mode, the element
18349      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18350      * was dropped on.
18351      */
18352     onDragDrop: function(e, id) { /* override this */ },
18353
18354     /**
18355      * Abstract method called when this item is dropped on an area with no
18356      * drop target
18357      * @method onInvalidDrop
18358      * @param {Event} e the mouseup event
18359      */
18360     onInvalidDrop: function(e) { /* override this */ },
18361
18362     /**
18363      * Code that executes immediately before the endDrag event
18364      * @method b4EndDrag
18365      * @private
18366      */
18367     b4EndDrag: function(e) { },
18368
18369     /**
18370      * Fired when we are done dragging the object
18371      * @method endDrag
18372      * @param {Event} e the mouseup event
18373      */
18374     endDrag: function(e) { /* override this */ },
18375
18376     /**
18377      * Code executed immediately before the onMouseDown event
18378      * @method b4MouseDown
18379      * @param {Event} e the mousedown event
18380      * @private
18381      */
18382     b4MouseDown: function(e) {  },
18383
18384     /**
18385      * Event handler that fires when a drag/drop obj gets a mousedown
18386      * @method onMouseDown
18387      * @param {Event} e the mousedown event
18388      */
18389     onMouseDown: function(e) { /* override this */ },
18390
18391     /**
18392      * Event handler that fires when a drag/drop obj gets a mouseup
18393      * @method onMouseUp
18394      * @param {Event} e the mouseup event
18395      */
18396     onMouseUp: function(e) { /* override this */ },
18397
18398     /**
18399      * Override the onAvailable method to do what is needed after the initial
18400      * position was determined.
18401      * @method onAvailable
18402      */
18403     onAvailable: function () {
18404     },
18405
18406     /*
18407      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18408      * @type Object
18409      */
18410     defaultPadding : {left:0, right:0, top:0, bottom:0},
18411
18412     /*
18413      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18414  *
18415  * Usage:
18416  <pre><code>
18417  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18418                 { dragElId: "existingProxyDiv" });
18419  dd.startDrag = function(){
18420      this.constrainTo("parent-id");
18421  };
18422  </code></pre>
18423  * Or you can initalize it using the {@link Roo.Element} object:
18424  <pre><code>
18425  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18426      startDrag : function(){
18427          this.constrainTo("parent-id");
18428      }
18429  });
18430  </code></pre>
18431      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18432      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18433      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18434      * an object containing the sides to pad. For example: {right:10, bottom:10}
18435      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18436      */
18437     constrainTo : function(constrainTo, pad, inContent){
18438         if(typeof pad == "number"){
18439             pad = {left: pad, right:pad, top:pad, bottom:pad};
18440         }
18441         pad = pad || this.defaultPadding;
18442         var b = Roo.get(this.getEl()).getBox();
18443         var ce = Roo.get(constrainTo);
18444         var s = ce.getScroll();
18445         var c, cd = ce.dom;
18446         if(cd == document.body){
18447             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18448         }else{
18449             xy = ce.getXY();
18450             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18451         }
18452
18453
18454         var topSpace = b.y - c.y;
18455         var leftSpace = b.x - c.x;
18456
18457         this.resetConstraints();
18458         this.setXConstraint(leftSpace - (pad.left||0), // left
18459                 c.width - leftSpace - b.width - (pad.right||0) //right
18460         );
18461         this.setYConstraint(topSpace - (pad.top||0), //top
18462                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18463         );
18464     },
18465
18466     /**
18467      * Returns a reference to the linked element
18468      * @method getEl
18469      * @return {HTMLElement} the html element
18470      */
18471     getEl: function() {
18472         if (!this._domRef) {
18473             this._domRef = Roo.getDom(this.id);
18474         }
18475
18476         return this._domRef;
18477     },
18478
18479     /**
18480      * Returns a reference to the actual element to drag.  By default this is
18481      * the same as the html element, but it can be assigned to another
18482      * element. An example of this can be found in Roo.dd.DDProxy
18483      * @method getDragEl
18484      * @return {HTMLElement} the html element
18485      */
18486     getDragEl: function() {
18487         return Roo.getDom(this.dragElId);
18488     },
18489
18490     /**
18491      * Sets up the DragDrop object.  Must be called in the constructor of any
18492      * Roo.dd.DragDrop subclass
18493      * @method init
18494      * @param id the id of the linked element
18495      * @param {String} sGroup the group of related items
18496      * @param {object} config configuration attributes
18497      */
18498     init: function(id, sGroup, config) {
18499         this.initTarget(id, sGroup, config);
18500         if (!Roo.isTouch) {
18501             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18502         }
18503         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18504         // Event.on(this.id, "selectstart", Event.preventDefault);
18505     },
18506
18507     /**
18508      * Initializes Targeting functionality only... the object does not
18509      * get a mousedown handler.
18510      * @method initTarget
18511      * @param id the id of the linked element
18512      * @param {String} sGroup the group of related items
18513      * @param {object} config configuration attributes
18514      */
18515     initTarget: function(id, sGroup, config) {
18516
18517         // configuration attributes
18518         this.config = config || {};
18519
18520         // create a local reference to the drag and drop manager
18521         this.DDM = Roo.dd.DDM;
18522         // initialize the groups array
18523         this.groups = {};
18524
18525         // assume that we have an element reference instead of an id if the
18526         // parameter is not a string
18527         if (typeof id !== "string") {
18528             id = Roo.id(id);
18529         }
18530
18531         // set the id
18532         this.id = id;
18533
18534         // add to an interaction group
18535         this.addToGroup((sGroup) ? sGroup : "default");
18536
18537         // We don't want to register this as the handle with the manager
18538         // so we just set the id rather than calling the setter.
18539         this.handleElId = id;
18540
18541         // the linked element is the element that gets dragged by default
18542         this.setDragElId(id);
18543
18544         // by default, clicked anchors will not start drag operations.
18545         this.invalidHandleTypes = { A: "A" };
18546         this.invalidHandleIds = {};
18547         this.invalidHandleClasses = [];
18548
18549         this.applyConfig();
18550
18551         this.handleOnAvailable();
18552     },
18553
18554     /**
18555      * Applies the configuration parameters that were passed into the constructor.
18556      * This is supposed to happen at each level through the inheritance chain.  So
18557      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18558      * DragDrop in order to get all of the parameters that are available in
18559      * each object.
18560      * @method applyConfig
18561      */
18562     applyConfig: function() {
18563
18564         // configurable properties:
18565         //    padding, isTarget, maintainOffset, primaryButtonOnly
18566         this.padding           = this.config.padding || [0, 0, 0, 0];
18567         this.isTarget          = (this.config.isTarget !== false);
18568         this.maintainOffset    = (this.config.maintainOffset);
18569         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18570
18571     },
18572
18573     /**
18574      * Executed when the linked element is available
18575      * @method handleOnAvailable
18576      * @private
18577      */
18578     handleOnAvailable: function() {
18579         this.available = true;
18580         this.resetConstraints();
18581         this.onAvailable();
18582     },
18583
18584      /**
18585      * Configures the padding for the target zone in px.  Effectively expands
18586      * (or reduces) the virtual object size for targeting calculations.
18587      * Supports css-style shorthand; if only one parameter is passed, all sides
18588      * will have that padding, and if only two are passed, the top and bottom
18589      * will have the first param, the left and right the second.
18590      * @method setPadding
18591      * @param {int} iTop    Top pad
18592      * @param {int} iRight  Right pad
18593      * @param {int} iBot    Bot pad
18594      * @param {int} iLeft   Left pad
18595      */
18596     setPadding: function(iTop, iRight, iBot, iLeft) {
18597         // this.padding = [iLeft, iRight, iTop, iBot];
18598         if (!iRight && 0 !== iRight) {
18599             this.padding = [iTop, iTop, iTop, iTop];
18600         } else if (!iBot && 0 !== iBot) {
18601             this.padding = [iTop, iRight, iTop, iRight];
18602         } else {
18603             this.padding = [iTop, iRight, iBot, iLeft];
18604         }
18605     },
18606
18607     /**
18608      * Stores the initial placement of the linked element.
18609      * @method setInitialPosition
18610      * @param {int} diffX   the X offset, default 0
18611      * @param {int} diffY   the Y offset, default 0
18612      */
18613     setInitPosition: function(diffX, diffY) {
18614         var el = this.getEl();
18615
18616         if (!this.DDM.verifyEl(el)) {
18617             return;
18618         }
18619
18620         var dx = diffX || 0;
18621         var dy = diffY || 0;
18622
18623         var p = Dom.getXY( el );
18624
18625         this.initPageX = p[0] - dx;
18626         this.initPageY = p[1] - dy;
18627
18628         this.lastPageX = p[0];
18629         this.lastPageY = p[1];
18630
18631
18632         this.setStartPosition(p);
18633     },
18634
18635     /**
18636      * Sets the start position of the element.  This is set when the obj
18637      * is initialized, the reset when a drag is started.
18638      * @method setStartPosition
18639      * @param pos current position (from previous lookup)
18640      * @private
18641      */
18642     setStartPosition: function(pos) {
18643         var p = pos || Dom.getXY( this.getEl() );
18644         this.deltaSetXY = null;
18645
18646         this.startPageX = p[0];
18647         this.startPageY = p[1];
18648     },
18649
18650     /**
18651      * Add this instance to a group of related drag/drop objects.  All
18652      * instances belong to at least one group, and can belong to as many
18653      * groups as needed.
18654      * @method addToGroup
18655      * @param sGroup {string} the name of the group
18656      */
18657     addToGroup: function(sGroup) {
18658         this.groups[sGroup] = true;
18659         this.DDM.regDragDrop(this, sGroup);
18660     },
18661
18662     /**
18663      * Remove's this instance from the supplied interaction group
18664      * @method removeFromGroup
18665      * @param {string}  sGroup  The group to drop
18666      */
18667     removeFromGroup: function(sGroup) {
18668         if (this.groups[sGroup]) {
18669             delete this.groups[sGroup];
18670         }
18671
18672         this.DDM.removeDDFromGroup(this, sGroup);
18673     },
18674
18675     /**
18676      * Allows you to specify that an element other than the linked element
18677      * will be moved with the cursor during a drag
18678      * @method setDragElId
18679      * @param id {string} the id of the element that will be used to initiate the drag
18680      */
18681     setDragElId: function(id) {
18682         this.dragElId = id;
18683     },
18684
18685     /**
18686      * Allows you to specify a child of the linked element that should be
18687      * used to initiate the drag operation.  An example of this would be if
18688      * you have a content div with text and links.  Clicking anywhere in the
18689      * content area would normally start the drag operation.  Use this method
18690      * to specify that an element inside of the content div is the element
18691      * that starts the drag operation.
18692      * @method setHandleElId
18693      * @param id {string} the id of the element that will be used to
18694      * initiate the drag.
18695      */
18696     setHandleElId: function(id) {
18697         if (typeof id !== "string") {
18698             id = Roo.id(id);
18699         }
18700         this.handleElId = id;
18701         this.DDM.regHandle(this.id, id);
18702     },
18703
18704     /**
18705      * Allows you to set an element outside of the linked element as a drag
18706      * handle
18707      * @method setOuterHandleElId
18708      * @param id the id of the element that will be used to initiate the drag
18709      */
18710     setOuterHandleElId: function(id) {
18711         if (typeof id !== "string") {
18712             id = Roo.id(id);
18713         }
18714         Event.on(id, "mousedown",
18715                 this.handleMouseDown, this);
18716         this.setHandleElId(id);
18717
18718         this.hasOuterHandles = true;
18719     },
18720
18721     /**
18722      * Remove all drag and drop hooks for this element
18723      * @method unreg
18724      */
18725     unreg: function() {
18726         Event.un(this.id, "mousedown",
18727                 this.handleMouseDown);
18728         Event.un(this.id, "touchstart",
18729                 this.handleMouseDown);
18730         this._domRef = null;
18731         this.DDM._remove(this);
18732     },
18733
18734     destroy : function(){
18735         this.unreg();
18736     },
18737
18738     /**
18739      * Returns true if this instance is locked, or the drag drop mgr is locked
18740      * (meaning that all drag/drop is disabled on the page.)
18741      * @method isLocked
18742      * @return {boolean} true if this obj or all drag/drop is locked, else
18743      * false
18744      */
18745     isLocked: function() {
18746         return (this.DDM.isLocked() || this.locked);
18747     },
18748
18749     /**
18750      * Fired when this object is clicked
18751      * @method handleMouseDown
18752      * @param {Event} e
18753      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18754      * @private
18755      */
18756     handleMouseDown: function(e, oDD){
18757      
18758         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18759             //Roo.log('not touch/ button !=0');
18760             return;
18761         }
18762         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18763             return; // double touch..
18764         }
18765         
18766
18767         if (this.isLocked()) {
18768             //Roo.log('locked');
18769             return;
18770         }
18771
18772         this.DDM.refreshCache(this.groups);
18773 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18774         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18775         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18776             //Roo.log('no outer handes or not over target');
18777                 // do nothing.
18778         } else {
18779 //            Roo.log('check validator');
18780             if (this.clickValidator(e)) {
18781 //                Roo.log('validate success');
18782                 // set the initial element position
18783                 this.setStartPosition();
18784
18785
18786                 this.b4MouseDown(e);
18787                 this.onMouseDown(e);
18788
18789                 this.DDM.handleMouseDown(e, this);
18790
18791                 this.DDM.stopEvent(e);
18792             } else {
18793
18794
18795             }
18796         }
18797     },
18798
18799     clickValidator: function(e) {
18800         var target = e.getTarget();
18801         return ( this.isValidHandleChild(target) &&
18802                     (this.id == this.handleElId ||
18803                         this.DDM.handleWasClicked(target, this.id)) );
18804     },
18805
18806     /**
18807      * Allows you to specify a tag name that should not start a drag operation
18808      * when clicked.  This is designed to facilitate embedding links within a
18809      * drag handle that do something other than start the drag.
18810      * @method addInvalidHandleType
18811      * @param {string} tagName the type of element to exclude
18812      */
18813     addInvalidHandleType: function(tagName) {
18814         var type = tagName.toUpperCase();
18815         this.invalidHandleTypes[type] = type;
18816     },
18817
18818     /**
18819      * Lets you to specify an element id for a child of a drag handle
18820      * that should not initiate a drag
18821      * @method addInvalidHandleId
18822      * @param {string} id the element id of the element you wish to ignore
18823      */
18824     addInvalidHandleId: function(id) {
18825         if (typeof id !== "string") {
18826             id = Roo.id(id);
18827         }
18828         this.invalidHandleIds[id] = id;
18829     },
18830
18831     /**
18832      * Lets you specify a css class of elements that will not initiate a drag
18833      * @method addInvalidHandleClass
18834      * @param {string} cssClass the class of the elements you wish to ignore
18835      */
18836     addInvalidHandleClass: function(cssClass) {
18837         this.invalidHandleClasses.push(cssClass);
18838     },
18839
18840     /**
18841      * Unsets an excluded tag name set by addInvalidHandleType
18842      * @method removeInvalidHandleType
18843      * @param {string} tagName the type of element to unexclude
18844      */
18845     removeInvalidHandleType: function(tagName) {
18846         var type = tagName.toUpperCase();
18847         // this.invalidHandleTypes[type] = null;
18848         delete this.invalidHandleTypes[type];
18849     },
18850
18851     /**
18852      * Unsets an invalid handle id
18853      * @method removeInvalidHandleId
18854      * @param {string} id the id of the element to re-enable
18855      */
18856     removeInvalidHandleId: function(id) {
18857         if (typeof id !== "string") {
18858             id = Roo.id(id);
18859         }
18860         delete this.invalidHandleIds[id];
18861     },
18862
18863     /**
18864      * Unsets an invalid css class
18865      * @method removeInvalidHandleClass
18866      * @param {string} cssClass the class of the element(s) you wish to
18867      * re-enable
18868      */
18869     removeInvalidHandleClass: function(cssClass) {
18870         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18871             if (this.invalidHandleClasses[i] == cssClass) {
18872                 delete this.invalidHandleClasses[i];
18873             }
18874         }
18875     },
18876
18877     /**
18878      * Checks the tag exclusion list to see if this click should be ignored
18879      * @method isValidHandleChild
18880      * @param {HTMLElement} node the HTMLElement to evaluate
18881      * @return {boolean} true if this is a valid tag type, false if not
18882      */
18883     isValidHandleChild: function(node) {
18884
18885         var valid = true;
18886         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18887         var nodeName;
18888         try {
18889             nodeName = node.nodeName.toUpperCase();
18890         } catch(e) {
18891             nodeName = node.nodeName;
18892         }
18893         valid = valid && !this.invalidHandleTypes[nodeName];
18894         valid = valid && !this.invalidHandleIds[node.id];
18895
18896         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18897             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18898         }
18899
18900
18901         return valid;
18902
18903     },
18904
18905     /**
18906      * Create the array of horizontal tick marks if an interval was specified
18907      * in setXConstraint().
18908      * @method setXTicks
18909      * @private
18910      */
18911     setXTicks: function(iStartX, iTickSize) {
18912         this.xTicks = [];
18913         this.xTickSize = iTickSize;
18914
18915         var tickMap = {};
18916
18917         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18918             if (!tickMap[i]) {
18919                 this.xTicks[this.xTicks.length] = i;
18920                 tickMap[i] = true;
18921             }
18922         }
18923
18924         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18925             if (!tickMap[i]) {
18926                 this.xTicks[this.xTicks.length] = i;
18927                 tickMap[i] = true;
18928             }
18929         }
18930
18931         this.xTicks.sort(this.DDM.numericSort) ;
18932     },
18933
18934     /**
18935      * Create the array of vertical tick marks if an interval was specified in
18936      * setYConstraint().
18937      * @method setYTicks
18938      * @private
18939      */
18940     setYTicks: function(iStartY, iTickSize) {
18941         this.yTicks = [];
18942         this.yTickSize = iTickSize;
18943
18944         var tickMap = {};
18945
18946         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18947             if (!tickMap[i]) {
18948                 this.yTicks[this.yTicks.length] = i;
18949                 tickMap[i] = true;
18950             }
18951         }
18952
18953         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18954             if (!tickMap[i]) {
18955                 this.yTicks[this.yTicks.length] = i;
18956                 tickMap[i] = true;
18957             }
18958         }
18959
18960         this.yTicks.sort(this.DDM.numericSort) ;
18961     },
18962
18963     /**
18964      * By default, the element can be dragged any place on the screen.  Use
18965      * this method to limit the horizontal travel of the element.  Pass in
18966      * 0,0 for the parameters if you want to lock the drag to the y axis.
18967      * @method setXConstraint
18968      * @param {int} iLeft the number of pixels the element can move to the left
18969      * @param {int} iRight the number of pixels the element can move to the
18970      * right
18971      * @param {int} iTickSize optional parameter for specifying that the
18972      * element
18973      * should move iTickSize pixels at a time.
18974      */
18975     setXConstraint: function(iLeft, iRight, iTickSize) {
18976         this.leftConstraint = iLeft;
18977         this.rightConstraint = iRight;
18978
18979         this.minX = this.initPageX - iLeft;
18980         this.maxX = this.initPageX + iRight;
18981         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18982
18983         this.constrainX = true;
18984     },
18985
18986     /**
18987      * Clears any constraints applied to this instance.  Also clears ticks
18988      * since they can't exist independent of a constraint at this time.
18989      * @method clearConstraints
18990      */
18991     clearConstraints: function() {
18992         this.constrainX = false;
18993         this.constrainY = false;
18994         this.clearTicks();
18995     },
18996
18997     /**
18998      * Clears any tick interval defined for this instance
18999      * @method clearTicks
19000      */
19001     clearTicks: function() {
19002         this.xTicks = null;
19003         this.yTicks = null;
19004         this.xTickSize = 0;
19005         this.yTickSize = 0;
19006     },
19007
19008     /**
19009      * By default, the element can be dragged any place on the screen.  Set
19010      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19011      * parameters if you want to lock the drag to the x axis.
19012      * @method setYConstraint
19013      * @param {int} iUp the number of pixels the element can move up
19014      * @param {int} iDown the number of pixels the element can move down
19015      * @param {int} iTickSize optional parameter for specifying that the
19016      * element should move iTickSize pixels at a time.
19017      */
19018     setYConstraint: function(iUp, iDown, iTickSize) {
19019         this.topConstraint = iUp;
19020         this.bottomConstraint = iDown;
19021
19022         this.minY = this.initPageY - iUp;
19023         this.maxY = this.initPageY + iDown;
19024         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19025
19026         this.constrainY = true;
19027
19028     },
19029
19030     /**
19031      * resetConstraints must be called if you manually reposition a dd element.
19032      * @method resetConstraints
19033      * @param {boolean} maintainOffset
19034      */
19035     resetConstraints: function() {
19036
19037
19038         // Maintain offsets if necessary
19039         if (this.initPageX || this.initPageX === 0) {
19040             // figure out how much this thing has moved
19041             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19042             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19043
19044             this.setInitPosition(dx, dy);
19045
19046         // This is the first time we have detected the element's position
19047         } else {
19048             this.setInitPosition();
19049         }
19050
19051         if (this.constrainX) {
19052             this.setXConstraint( this.leftConstraint,
19053                                  this.rightConstraint,
19054                                  this.xTickSize        );
19055         }
19056
19057         if (this.constrainY) {
19058             this.setYConstraint( this.topConstraint,
19059                                  this.bottomConstraint,
19060                                  this.yTickSize         );
19061         }
19062     },
19063
19064     /**
19065      * Normally the drag element is moved pixel by pixel, but we can specify
19066      * that it move a number of pixels at a time.  This method resolves the
19067      * location when we have it set up like this.
19068      * @method getTick
19069      * @param {int} val where we want to place the object
19070      * @param {int[]} tickArray sorted array of valid points
19071      * @return {int} the closest tick
19072      * @private
19073      */
19074     getTick: function(val, tickArray) {
19075
19076         if (!tickArray) {
19077             // If tick interval is not defined, it is effectively 1 pixel,
19078             // so we return the value passed to us.
19079             return val;
19080         } else if (tickArray[0] >= val) {
19081             // The value is lower than the first tick, so we return the first
19082             // tick.
19083             return tickArray[0];
19084         } else {
19085             for (var i=0, len=tickArray.length; i<len; ++i) {
19086                 var next = i + 1;
19087                 if (tickArray[next] && tickArray[next] >= val) {
19088                     var diff1 = val - tickArray[i];
19089                     var diff2 = tickArray[next] - val;
19090                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19091                 }
19092             }
19093
19094             // The value is larger than the last tick, so we return the last
19095             // tick.
19096             return tickArray[tickArray.length - 1];
19097         }
19098     },
19099
19100     /**
19101      * toString method
19102      * @method toString
19103      * @return {string} string representation of the dd obj
19104      */
19105     toString: function() {
19106         return ("DragDrop " + this.id);
19107     }
19108
19109 });
19110
19111 })();
19112 /*
19113  * Based on:
19114  * Ext JS Library 1.1.1
19115  * Copyright(c) 2006-2007, Ext JS, LLC.
19116  *
19117  * Originally Released Under LGPL - original licence link has changed is not relivant.
19118  *
19119  * Fork - LGPL
19120  * <script type="text/javascript">
19121  */
19122
19123
19124 /**
19125  * The drag and drop utility provides a framework for building drag and drop
19126  * applications.  In addition to enabling drag and drop for specific elements,
19127  * the drag and drop elements are tracked by the manager class, and the
19128  * interactions between the various elements are tracked during the drag and
19129  * the implementing code is notified about these important moments.
19130  */
19131
19132 // Only load the library once.  Rewriting the manager class would orphan
19133 // existing drag and drop instances.
19134 if (!Roo.dd.DragDropMgr) {
19135
19136 /**
19137  * @class Roo.dd.DragDropMgr
19138  * DragDropMgr is a singleton that tracks the element interaction for
19139  * all DragDrop items in the window.  Generally, you will not call
19140  * this class directly, but it does have helper methods that could
19141  * be useful in your DragDrop implementations.
19142  * @singleton
19143  */
19144 Roo.dd.DragDropMgr = function() {
19145
19146     var Event = Roo.EventManager;
19147
19148     return {
19149
19150         /**
19151          * Two dimensional Array of registered DragDrop objects.  The first
19152          * dimension is the DragDrop item group, the second the DragDrop
19153          * object.
19154          * @property ids
19155          * @type {string: string}
19156          * @private
19157          * @static
19158          */
19159         ids: {},
19160
19161         /**
19162          * Array of element ids defined as drag handles.  Used to determine
19163          * if the element that generated the mousedown event is actually the
19164          * handle and not the html element itself.
19165          * @property handleIds
19166          * @type {string: string}
19167          * @private
19168          * @static
19169          */
19170         handleIds: {},
19171
19172         /**
19173          * the DragDrop object that is currently being dragged
19174          * @property dragCurrent
19175          * @type DragDrop
19176          * @private
19177          * @static
19178          **/
19179         dragCurrent: null,
19180
19181         /**
19182          * the DragDrop object(s) that are being hovered over
19183          * @property dragOvers
19184          * @type Array
19185          * @private
19186          * @static
19187          */
19188         dragOvers: {},
19189
19190         /**
19191          * the X distance between the cursor and the object being dragged
19192          * @property deltaX
19193          * @type int
19194          * @private
19195          * @static
19196          */
19197         deltaX: 0,
19198
19199         /**
19200          * the Y distance between the cursor and the object being dragged
19201          * @property deltaY
19202          * @type int
19203          * @private
19204          * @static
19205          */
19206         deltaY: 0,
19207
19208         /**
19209          * Flag to determine if we should prevent the default behavior of the
19210          * events we define. By default this is true, but this can be set to
19211          * false if you need the default behavior (not recommended)
19212          * @property preventDefault
19213          * @type boolean
19214          * @static
19215          */
19216         preventDefault: true,
19217
19218         /**
19219          * Flag to determine if we should stop the propagation of the events
19220          * we generate. This is true by default but you may want to set it to
19221          * false if the html element contains other features that require the
19222          * mouse click.
19223          * @property stopPropagation
19224          * @type boolean
19225          * @static
19226          */
19227         stopPropagation: true,
19228
19229         /**
19230          * Internal flag that is set to true when drag and drop has been
19231          * intialized
19232          * @property initialized
19233          * @private
19234          * @static
19235          */
19236         initalized: false,
19237
19238         /**
19239          * All drag and drop can be disabled.
19240          * @property locked
19241          * @private
19242          * @static
19243          */
19244         locked: false,
19245
19246         /**
19247          * Called the first time an element is registered.
19248          * @method init
19249          * @private
19250          * @static
19251          */
19252         init: function() {
19253             this.initialized = true;
19254         },
19255
19256         /**
19257          * In point mode, drag and drop interaction is defined by the
19258          * location of the cursor during the drag/drop
19259          * @property POINT
19260          * @type int
19261          * @static
19262          */
19263         POINT: 0,
19264
19265         /**
19266          * In intersect mode, drag and drop interactio nis defined by the
19267          * overlap of two or more drag and drop objects.
19268          * @property INTERSECT
19269          * @type int
19270          * @static
19271          */
19272         INTERSECT: 1,
19273
19274         /**
19275          * The current drag and drop mode.  Default: POINT
19276          * @property mode
19277          * @type int
19278          * @static
19279          */
19280         mode: 0,
19281
19282         /**
19283          * Runs method on all drag and drop objects
19284          * @method _execOnAll
19285          * @private
19286          * @static
19287          */
19288         _execOnAll: function(sMethod, args) {
19289             for (var i in this.ids) {
19290                 for (var j in this.ids[i]) {
19291                     var oDD = this.ids[i][j];
19292                     if (! this.isTypeOfDD(oDD)) {
19293                         continue;
19294                     }
19295                     oDD[sMethod].apply(oDD, args);
19296                 }
19297             }
19298         },
19299
19300         /**
19301          * Drag and drop initialization.  Sets up the global event handlers
19302          * @method _onLoad
19303          * @private
19304          * @static
19305          */
19306         _onLoad: function() {
19307
19308             this.init();
19309
19310             if (!Roo.isTouch) {
19311                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19312                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19313             }
19314             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19315             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19316             
19317             Event.on(window,   "unload",    this._onUnload, this, true);
19318             Event.on(window,   "resize",    this._onResize, this, true);
19319             // Event.on(window,   "mouseout",    this._test);
19320
19321         },
19322
19323         /**
19324          * Reset constraints on all drag and drop objs
19325          * @method _onResize
19326          * @private
19327          * @static
19328          */
19329         _onResize: function(e) {
19330             this._execOnAll("resetConstraints", []);
19331         },
19332
19333         /**
19334          * Lock all drag and drop functionality
19335          * @method lock
19336          * @static
19337          */
19338         lock: function() { this.locked = true; },
19339
19340         /**
19341          * Unlock all drag and drop functionality
19342          * @method unlock
19343          * @static
19344          */
19345         unlock: function() { this.locked = false; },
19346
19347         /**
19348          * Is drag and drop locked?
19349          * @method isLocked
19350          * @return {boolean} True if drag and drop is locked, false otherwise.
19351          * @static
19352          */
19353         isLocked: function() { return this.locked; },
19354
19355         /**
19356          * Location cache that is set for all drag drop objects when a drag is
19357          * initiated, cleared when the drag is finished.
19358          * @property locationCache
19359          * @private
19360          * @static
19361          */
19362         locationCache: {},
19363
19364         /**
19365          * Set useCache to false if you want to force object the lookup of each
19366          * drag and drop linked element constantly during a drag.
19367          * @property useCache
19368          * @type boolean
19369          * @static
19370          */
19371         useCache: true,
19372
19373         /**
19374          * The number of pixels that the mouse needs to move after the
19375          * mousedown before the drag is initiated.  Default=3;
19376          * @property clickPixelThresh
19377          * @type int
19378          * @static
19379          */
19380         clickPixelThresh: 3,
19381
19382         /**
19383          * The number of milliseconds after the mousedown event to initiate the
19384          * drag if we don't get a mouseup event. Default=1000
19385          * @property clickTimeThresh
19386          * @type int
19387          * @static
19388          */
19389         clickTimeThresh: 350,
19390
19391         /**
19392          * Flag that indicates that either the drag pixel threshold or the
19393          * mousdown time threshold has been met
19394          * @property dragThreshMet
19395          * @type boolean
19396          * @private
19397          * @static
19398          */
19399         dragThreshMet: false,
19400
19401         /**
19402          * Timeout used for the click time threshold
19403          * @property clickTimeout
19404          * @type Object
19405          * @private
19406          * @static
19407          */
19408         clickTimeout: null,
19409
19410         /**
19411          * The X position of the mousedown event stored for later use when a
19412          * drag threshold is met.
19413          * @property startX
19414          * @type int
19415          * @private
19416          * @static
19417          */
19418         startX: 0,
19419
19420         /**
19421          * The Y position of the mousedown event stored for later use when a
19422          * drag threshold is met.
19423          * @property startY
19424          * @type int
19425          * @private
19426          * @static
19427          */
19428         startY: 0,
19429
19430         /**
19431          * Each DragDrop instance must be registered with the DragDropMgr.
19432          * This is executed in DragDrop.init()
19433          * @method regDragDrop
19434          * @param {DragDrop} oDD the DragDrop object to register
19435          * @param {String} sGroup the name of the group this element belongs to
19436          * @static
19437          */
19438         regDragDrop: function(oDD, sGroup) {
19439             if (!this.initialized) { this.init(); }
19440
19441             if (!this.ids[sGroup]) {
19442                 this.ids[sGroup] = {};
19443             }
19444             this.ids[sGroup][oDD.id] = oDD;
19445         },
19446
19447         /**
19448          * Removes the supplied dd instance from the supplied group. Executed
19449          * by DragDrop.removeFromGroup, so don't call this function directly.
19450          * @method removeDDFromGroup
19451          * @private
19452          * @static
19453          */
19454         removeDDFromGroup: function(oDD, sGroup) {
19455             if (!this.ids[sGroup]) {
19456                 this.ids[sGroup] = {};
19457             }
19458
19459             var obj = this.ids[sGroup];
19460             if (obj && obj[oDD.id]) {
19461                 delete obj[oDD.id];
19462             }
19463         },
19464
19465         /**
19466          * Unregisters a drag and drop item.  This is executed in
19467          * DragDrop.unreg, use that method instead of calling this directly.
19468          * @method _remove
19469          * @private
19470          * @static
19471          */
19472         _remove: function(oDD) {
19473             for (var g in oDD.groups) {
19474                 if (g && this.ids[g][oDD.id]) {
19475                     delete this.ids[g][oDD.id];
19476                 }
19477             }
19478             delete this.handleIds[oDD.id];
19479         },
19480
19481         /**
19482          * Each DragDrop handle element must be registered.  This is done
19483          * automatically when executing DragDrop.setHandleElId()
19484          * @method regHandle
19485          * @param {String} sDDId the DragDrop id this element is a handle for
19486          * @param {String} sHandleId the id of the element that is the drag
19487          * handle
19488          * @static
19489          */
19490         regHandle: function(sDDId, sHandleId) {
19491             if (!this.handleIds[sDDId]) {
19492                 this.handleIds[sDDId] = {};
19493             }
19494             this.handleIds[sDDId][sHandleId] = sHandleId;
19495         },
19496
19497         /**
19498          * Utility function to determine if a given element has been
19499          * registered as a drag drop item.
19500          * @method isDragDrop
19501          * @param {String} id the element id to check
19502          * @return {boolean} true if this element is a DragDrop item,
19503          * false otherwise
19504          * @static
19505          */
19506         isDragDrop: function(id) {
19507             return ( this.getDDById(id) ) ? true : false;
19508         },
19509
19510         /**
19511          * Returns the drag and drop instances that are in all groups the
19512          * passed in instance belongs to.
19513          * @method getRelated
19514          * @param {DragDrop} p_oDD the obj to get related data for
19515          * @param {boolean} bTargetsOnly if true, only return targetable objs
19516          * @return {DragDrop[]} the related instances
19517          * @static
19518          */
19519         getRelated: function(p_oDD, bTargetsOnly) {
19520             var oDDs = [];
19521             for (var i in p_oDD.groups) {
19522                 for (j in this.ids[i]) {
19523                     var dd = this.ids[i][j];
19524                     if (! this.isTypeOfDD(dd)) {
19525                         continue;
19526                     }
19527                     if (!bTargetsOnly || dd.isTarget) {
19528                         oDDs[oDDs.length] = dd;
19529                     }
19530                 }
19531             }
19532
19533             return oDDs;
19534         },
19535
19536         /**
19537          * Returns true if the specified dd target is a legal target for
19538          * the specifice drag obj
19539          * @method isLegalTarget
19540          * @param {DragDrop} the drag obj
19541          * @param {DragDrop} the target
19542          * @return {boolean} true if the target is a legal target for the
19543          * dd obj
19544          * @static
19545          */
19546         isLegalTarget: function (oDD, oTargetDD) {
19547             var targets = this.getRelated(oDD, true);
19548             for (var i=0, len=targets.length;i<len;++i) {
19549                 if (targets[i].id == oTargetDD.id) {
19550                     return true;
19551                 }
19552             }
19553
19554             return false;
19555         },
19556
19557         /**
19558          * My goal is to be able to transparently determine if an object is
19559          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19560          * returns "object", oDD.constructor.toString() always returns
19561          * "DragDrop" and not the name of the subclass.  So for now it just
19562          * evaluates a well-known variable in DragDrop.
19563          * @method isTypeOfDD
19564          * @param {Object} the object to evaluate
19565          * @return {boolean} true if typeof oDD = DragDrop
19566          * @static
19567          */
19568         isTypeOfDD: function (oDD) {
19569             return (oDD && oDD.__ygDragDrop);
19570         },
19571
19572         /**
19573          * Utility function to determine if a given element has been
19574          * registered as a drag drop handle for the given Drag Drop object.
19575          * @method isHandle
19576          * @param {String} id the element id to check
19577          * @return {boolean} true if this element is a DragDrop handle, false
19578          * otherwise
19579          * @static
19580          */
19581         isHandle: function(sDDId, sHandleId) {
19582             return ( this.handleIds[sDDId] &&
19583                             this.handleIds[sDDId][sHandleId] );
19584         },
19585
19586         /**
19587          * Returns the DragDrop instance for a given id
19588          * @method getDDById
19589          * @param {String} id the id of the DragDrop object
19590          * @return {DragDrop} the drag drop object, null if it is not found
19591          * @static
19592          */
19593         getDDById: function(id) {
19594             for (var i in this.ids) {
19595                 if (this.ids[i][id]) {
19596                     return this.ids[i][id];
19597                 }
19598             }
19599             return null;
19600         },
19601
19602         /**
19603          * Fired after a registered DragDrop object gets the mousedown event.
19604          * Sets up the events required to track the object being dragged
19605          * @method handleMouseDown
19606          * @param {Event} e the event
19607          * @param oDD the DragDrop object being dragged
19608          * @private
19609          * @static
19610          */
19611         handleMouseDown: function(e, oDD) {
19612             if(Roo.QuickTips){
19613                 Roo.QuickTips.disable();
19614             }
19615             this.currentTarget = e.getTarget();
19616
19617             this.dragCurrent = oDD;
19618
19619             var el = oDD.getEl();
19620
19621             // track start position
19622             this.startX = e.getPageX();
19623             this.startY = e.getPageY();
19624
19625             this.deltaX = this.startX - el.offsetLeft;
19626             this.deltaY = this.startY - el.offsetTop;
19627
19628             this.dragThreshMet = false;
19629
19630             this.clickTimeout = setTimeout(
19631                     function() {
19632                         var DDM = Roo.dd.DDM;
19633                         DDM.startDrag(DDM.startX, DDM.startY);
19634                     },
19635                     this.clickTimeThresh );
19636         },
19637
19638         /**
19639          * Fired when either the drag pixel threshol or the mousedown hold
19640          * time threshold has been met.
19641          * @method startDrag
19642          * @param x {int} the X position of the original mousedown
19643          * @param y {int} the Y position of the original mousedown
19644          * @static
19645          */
19646         startDrag: function(x, y) {
19647             clearTimeout(this.clickTimeout);
19648             if (this.dragCurrent) {
19649                 this.dragCurrent.b4StartDrag(x, y);
19650                 this.dragCurrent.startDrag(x, y);
19651             }
19652             this.dragThreshMet = true;
19653         },
19654
19655         /**
19656          * Internal function to handle the mouseup event.  Will be invoked
19657          * from the context of the document.
19658          * @method handleMouseUp
19659          * @param {Event} e the event
19660          * @private
19661          * @static
19662          */
19663         handleMouseUp: function(e) {
19664
19665             if(Roo.QuickTips){
19666                 Roo.QuickTips.enable();
19667             }
19668             if (! this.dragCurrent) {
19669                 return;
19670             }
19671
19672             clearTimeout(this.clickTimeout);
19673
19674             if (this.dragThreshMet) {
19675                 this.fireEvents(e, true);
19676             } else {
19677             }
19678
19679             this.stopDrag(e);
19680
19681             this.stopEvent(e);
19682         },
19683
19684         /**
19685          * Utility to stop event propagation and event default, if these
19686          * features are turned on.
19687          * @method stopEvent
19688          * @param {Event} e the event as returned by this.getEvent()
19689          * @static
19690          */
19691         stopEvent: function(e){
19692             if(this.stopPropagation) {
19693                 e.stopPropagation();
19694             }
19695
19696             if (this.preventDefault) {
19697                 e.preventDefault();
19698             }
19699         },
19700
19701         /**
19702          * Internal function to clean up event handlers after the drag
19703          * operation is complete
19704          * @method stopDrag
19705          * @param {Event} e the event
19706          * @private
19707          * @static
19708          */
19709         stopDrag: function(e) {
19710             // Fire the drag end event for the item that was dragged
19711             if (this.dragCurrent) {
19712                 if (this.dragThreshMet) {
19713                     this.dragCurrent.b4EndDrag(e);
19714                     this.dragCurrent.endDrag(e);
19715                 }
19716
19717                 this.dragCurrent.onMouseUp(e);
19718             }
19719
19720             this.dragCurrent = null;
19721             this.dragOvers = {};
19722         },
19723
19724         /**
19725          * Internal function to handle the mousemove event.  Will be invoked
19726          * from the context of the html element.
19727          *
19728          * @TODO figure out what we can do about mouse events lost when the
19729          * user drags objects beyond the window boundary.  Currently we can
19730          * detect this in internet explorer by verifying that the mouse is
19731          * down during the mousemove event.  Firefox doesn't give us the
19732          * button state on the mousemove event.
19733          * @method handleMouseMove
19734          * @param {Event} e the event
19735          * @private
19736          * @static
19737          */
19738         handleMouseMove: function(e) {
19739             if (! this.dragCurrent) {
19740                 return true;
19741             }
19742
19743             // var button = e.which || e.button;
19744
19745             // check for IE mouseup outside of page boundary
19746             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19747                 this.stopEvent(e);
19748                 return this.handleMouseUp(e);
19749             }
19750
19751             if (!this.dragThreshMet) {
19752                 var diffX = Math.abs(this.startX - e.getPageX());
19753                 var diffY = Math.abs(this.startY - e.getPageY());
19754                 if (diffX > this.clickPixelThresh ||
19755                             diffY > this.clickPixelThresh) {
19756                     this.startDrag(this.startX, this.startY);
19757                 }
19758             }
19759
19760             if (this.dragThreshMet) {
19761                 this.dragCurrent.b4Drag(e);
19762                 this.dragCurrent.onDrag(e);
19763                 if(!this.dragCurrent.moveOnly){
19764                     this.fireEvents(e, false);
19765                 }
19766             }
19767
19768             this.stopEvent(e);
19769
19770             return true;
19771         },
19772
19773         /**
19774          * Iterates over all of the DragDrop elements to find ones we are
19775          * hovering over or dropping on
19776          * @method fireEvents
19777          * @param {Event} e the event
19778          * @param {boolean} isDrop is this a drop op or a mouseover op?
19779          * @private
19780          * @static
19781          */
19782         fireEvents: function(e, isDrop) {
19783             var dc = this.dragCurrent;
19784
19785             // If the user did the mouse up outside of the window, we could
19786             // get here even though we have ended the drag.
19787             if (!dc || dc.isLocked()) {
19788                 return;
19789             }
19790
19791             var pt = e.getPoint();
19792
19793             // cache the previous dragOver array
19794             var oldOvers = [];
19795
19796             var outEvts   = [];
19797             var overEvts  = [];
19798             var dropEvts  = [];
19799             var enterEvts = [];
19800
19801             // Check to see if the object(s) we were hovering over is no longer
19802             // being hovered over so we can fire the onDragOut event
19803             for (var i in this.dragOvers) {
19804
19805                 var ddo = this.dragOvers[i];
19806
19807                 if (! this.isTypeOfDD(ddo)) {
19808                     continue;
19809                 }
19810
19811                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19812                     outEvts.push( ddo );
19813                 }
19814
19815                 oldOvers[i] = true;
19816                 delete this.dragOvers[i];
19817             }
19818
19819             for (var sGroup in dc.groups) {
19820
19821                 if ("string" != typeof sGroup) {
19822                     continue;
19823                 }
19824
19825                 for (i in this.ids[sGroup]) {
19826                     var oDD = this.ids[sGroup][i];
19827                     if (! this.isTypeOfDD(oDD)) {
19828                         continue;
19829                     }
19830
19831                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19832                         if (this.isOverTarget(pt, oDD, this.mode)) {
19833                             // look for drop interactions
19834                             if (isDrop) {
19835                                 dropEvts.push( oDD );
19836                             // look for drag enter and drag over interactions
19837                             } else {
19838
19839                                 // initial drag over: dragEnter fires
19840                                 if (!oldOvers[oDD.id]) {
19841                                     enterEvts.push( oDD );
19842                                 // subsequent drag overs: dragOver fires
19843                                 } else {
19844                                     overEvts.push( oDD );
19845                                 }
19846
19847                                 this.dragOvers[oDD.id] = oDD;
19848                             }
19849                         }
19850                     }
19851                 }
19852             }
19853
19854             if (this.mode) {
19855                 if (outEvts.length) {
19856                     dc.b4DragOut(e, outEvts);
19857                     dc.onDragOut(e, outEvts);
19858                 }
19859
19860                 if (enterEvts.length) {
19861                     dc.onDragEnter(e, enterEvts);
19862                 }
19863
19864                 if (overEvts.length) {
19865                     dc.b4DragOver(e, overEvts);
19866                     dc.onDragOver(e, overEvts);
19867                 }
19868
19869                 if (dropEvts.length) {
19870                     dc.b4DragDrop(e, dropEvts);
19871                     dc.onDragDrop(e, dropEvts);
19872                 }
19873
19874             } else {
19875                 // fire dragout events
19876                 var len = 0;
19877                 for (i=0, len=outEvts.length; i<len; ++i) {
19878                     dc.b4DragOut(e, outEvts[i].id);
19879                     dc.onDragOut(e, outEvts[i].id);
19880                 }
19881
19882                 // fire enter events
19883                 for (i=0,len=enterEvts.length; i<len; ++i) {
19884                     // dc.b4DragEnter(e, oDD.id);
19885                     dc.onDragEnter(e, enterEvts[i].id);
19886                 }
19887
19888                 // fire over events
19889                 for (i=0,len=overEvts.length; i<len; ++i) {
19890                     dc.b4DragOver(e, overEvts[i].id);
19891                     dc.onDragOver(e, overEvts[i].id);
19892                 }
19893
19894                 // fire drop events
19895                 for (i=0, len=dropEvts.length; i<len; ++i) {
19896                     dc.b4DragDrop(e, dropEvts[i].id);
19897                     dc.onDragDrop(e, dropEvts[i].id);
19898                 }
19899
19900             }
19901
19902             // notify about a drop that did not find a target
19903             if (isDrop && !dropEvts.length) {
19904                 dc.onInvalidDrop(e);
19905             }
19906
19907         },
19908
19909         /**
19910          * Helper function for getting the best match from the list of drag
19911          * and drop objects returned by the drag and drop events when we are
19912          * in INTERSECT mode.  It returns either the first object that the
19913          * cursor is over, or the object that has the greatest overlap with
19914          * the dragged element.
19915          * @method getBestMatch
19916          * @param  {DragDrop[]} dds The array of drag and drop objects
19917          * targeted
19918          * @return {DragDrop}       The best single match
19919          * @static
19920          */
19921         getBestMatch: function(dds) {
19922             var winner = null;
19923             // Return null if the input is not what we expect
19924             //if (!dds || !dds.length || dds.length == 0) {
19925                // winner = null;
19926             // If there is only one item, it wins
19927             //} else if (dds.length == 1) {
19928
19929             var len = dds.length;
19930
19931             if (len == 1) {
19932                 winner = dds[0];
19933             } else {
19934                 // Loop through the targeted items
19935                 for (var i=0; i<len; ++i) {
19936                     var dd = dds[i];
19937                     // If the cursor is over the object, it wins.  If the
19938                     // cursor is over multiple matches, the first one we come
19939                     // to wins.
19940                     if (dd.cursorIsOver) {
19941                         winner = dd;
19942                         break;
19943                     // Otherwise the object with the most overlap wins
19944                     } else {
19945                         if (!winner ||
19946                             winner.overlap.getArea() < dd.overlap.getArea()) {
19947                             winner = dd;
19948                         }
19949                     }
19950                 }
19951             }
19952
19953             return winner;
19954         },
19955
19956         /**
19957          * Refreshes the cache of the top-left and bottom-right points of the
19958          * drag and drop objects in the specified group(s).  This is in the
19959          * format that is stored in the drag and drop instance, so typical
19960          * usage is:
19961          * <code>
19962          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19963          * </code>
19964          * Alternatively:
19965          * <code>
19966          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19967          * </code>
19968          * @TODO this really should be an indexed array.  Alternatively this
19969          * method could accept both.
19970          * @method refreshCache
19971          * @param {Object} groups an associative array of groups to refresh
19972          * @static
19973          */
19974         refreshCache: function(groups) {
19975             for (var sGroup in groups) {
19976                 if ("string" != typeof sGroup) {
19977                     continue;
19978                 }
19979                 for (var i in this.ids[sGroup]) {
19980                     var oDD = this.ids[sGroup][i];
19981
19982                     if (this.isTypeOfDD(oDD)) {
19983                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19984                         var loc = this.getLocation(oDD);
19985                         if (loc) {
19986                             this.locationCache[oDD.id] = loc;
19987                         } else {
19988                             delete this.locationCache[oDD.id];
19989                             // this will unregister the drag and drop object if
19990                             // the element is not in a usable state
19991                             // oDD.unreg();
19992                         }
19993                     }
19994                 }
19995             }
19996         },
19997
19998         /**
19999          * This checks to make sure an element exists and is in the DOM.  The
20000          * main purpose is to handle cases where innerHTML is used to remove
20001          * drag and drop objects from the DOM.  IE provides an 'unspecified
20002          * error' when trying to access the offsetParent of such an element
20003          * @method verifyEl
20004          * @param {HTMLElement} el the element to check
20005          * @return {boolean} true if the element looks usable
20006          * @static
20007          */
20008         verifyEl: function(el) {
20009             if (el) {
20010                 var parent;
20011                 if(Roo.isIE){
20012                     try{
20013                         parent = el.offsetParent;
20014                     }catch(e){}
20015                 }else{
20016                     parent = el.offsetParent;
20017                 }
20018                 if (parent) {
20019                     return true;
20020                 }
20021             }
20022
20023             return false;
20024         },
20025
20026         /**
20027          * Returns a Region object containing the drag and drop element's position
20028          * and size, including the padding configured for it
20029          * @method getLocation
20030          * @param {DragDrop} oDD the drag and drop object to get the
20031          *                       location for
20032          * @return {Roo.lib.Region} a Region object representing the total area
20033          *                             the element occupies, including any padding
20034          *                             the instance is configured for.
20035          * @static
20036          */
20037         getLocation: function(oDD) {
20038             if (! this.isTypeOfDD(oDD)) {
20039                 return null;
20040             }
20041
20042             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20043
20044             try {
20045                 pos= Roo.lib.Dom.getXY(el);
20046             } catch (e) { }
20047
20048             if (!pos) {
20049                 return null;
20050             }
20051
20052             x1 = pos[0];
20053             x2 = x1 + el.offsetWidth;
20054             y1 = pos[1];
20055             y2 = y1 + el.offsetHeight;
20056
20057             t = y1 - oDD.padding[0];
20058             r = x2 + oDD.padding[1];
20059             b = y2 + oDD.padding[2];
20060             l = x1 - oDD.padding[3];
20061
20062             return new Roo.lib.Region( t, r, b, l );
20063         },
20064
20065         /**
20066          * Checks the cursor location to see if it over the target
20067          * @method isOverTarget
20068          * @param {Roo.lib.Point} pt The point to evaluate
20069          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20070          * @return {boolean} true if the mouse is over the target
20071          * @private
20072          * @static
20073          */
20074         isOverTarget: function(pt, oTarget, intersect) {
20075             // use cache if available
20076             var loc = this.locationCache[oTarget.id];
20077             if (!loc || !this.useCache) {
20078                 loc = this.getLocation(oTarget);
20079                 this.locationCache[oTarget.id] = loc;
20080
20081             }
20082
20083             if (!loc) {
20084                 return false;
20085             }
20086
20087             oTarget.cursorIsOver = loc.contains( pt );
20088
20089             // DragDrop is using this as a sanity check for the initial mousedown
20090             // in this case we are done.  In POINT mode, if the drag obj has no
20091             // contraints, we are also done. Otherwise we need to evaluate the
20092             // location of the target as related to the actual location of the
20093             // dragged element.
20094             var dc = this.dragCurrent;
20095             if (!dc || !dc.getTargetCoord ||
20096                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20097                 return oTarget.cursorIsOver;
20098             }
20099
20100             oTarget.overlap = null;
20101
20102             // Get the current location of the drag element, this is the
20103             // location of the mouse event less the delta that represents
20104             // where the original mousedown happened on the element.  We
20105             // need to consider constraints and ticks as well.
20106             var pos = dc.getTargetCoord(pt.x, pt.y);
20107
20108             var el = dc.getDragEl();
20109             var curRegion = new Roo.lib.Region( pos.y,
20110                                                    pos.x + el.offsetWidth,
20111                                                    pos.y + el.offsetHeight,
20112                                                    pos.x );
20113
20114             var overlap = curRegion.intersect(loc);
20115
20116             if (overlap) {
20117                 oTarget.overlap = overlap;
20118                 return (intersect) ? true : oTarget.cursorIsOver;
20119             } else {
20120                 return false;
20121             }
20122         },
20123
20124         /**
20125          * unload event handler
20126          * @method _onUnload
20127          * @private
20128          * @static
20129          */
20130         _onUnload: function(e, me) {
20131             Roo.dd.DragDropMgr.unregAll();
20132         },
20133
20134         /**
20135          * Cleans up the drag and drop events and objects.
20136          * @method unregAll
20137          * @private
20138          * @static
20139          */
20140         unregAll: function() {
20141
20142             if (this.dragCurrent) {
20143                 this.stopDrag();
20144                 this.dragCurrent = null;
20145             }
20146
20147             this._execOnAll("unreg", []);
20148
20149             for (i in this.elementCache) {
20150                 delete this.elementCache[i];
20151             }
20152
20153             this.elementCache = {};
20154             this.ids = {};
20155         },
20156
20157         /**
20158          * A cache of DOM elements
20159          * @property elementCache
20160          * @private
20161          * @static
20162          */
20163         elementCache: {},
20164
20165         /**
20166          * Get the wrapper for the DOM element specified
20167          * @method getElWrapper
20168          * @param {String} id the id of the element to get
20169          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20170          * @private
20171          * @deprecated This wrapper isn't that useful
20172          * @static
20173          */
20174         getElWrapper: function(id) {
20175             var oWrapper = this.elementCache[id];
20176             if (!oWrapper || !oWrapper.el) {
20177                 oWrapper = this.elementCache[id] =
20178                     new this.ElementWrapper(Roo.getDom(id));
20179             }
20180             return oWrapper;
20181         },
20182
20183         /**
20184          * Returns the actual DOM element
20185          * @method getElement
20186          * @param {String} id the id of the elment to get
20187          * @return {Object} The element
20188          * @deprecated use Roo.getDom instead
20189          * @static
20190          */
20191         getElement: function(id) {
20192             return Roo.getDom(id);
20193         },
20194
20195         /**
20196          * Returns the style property for the DOM element (i.e.,
20197          * document.getElById(id).style)
20198          * @method getCss
20199          * @param {String} id the id of the elment to get
20200          * @return {Object} The style property of the element
20201          * @deprecated use Roo.getDom instead
20202          * @static
20203          */
20204         getCss: function(id) {
20205             var el = Roo.getDom(id);
20206             return (el) ? el.style : null;
20207         },
20208
20209         /**
20210          * Inner class for cached elements
20211          * @class DragDropMgr.ElementWrapper
20212          * @for DragDropMgr
20213          * @private
20214          * @deprecated
20215          */
20216         ElementWrapper: function(el) {
20217                 /**
20218                  * The element
20219                  * @property el
20220                  */
20221                 this.el = el || null;
20222                 /**
20223                  * The element id
20224                  * @property id
20225                  */
20226                 this.id = this.el && el.id;
20227                 /**
20228                  * A reference to the style property
20229                  * @property css
20230                  */
20231                 this.css = this.el && el.style;
20232             },
20233
20234         /**
20235          * Returns the X position of an html element
20236          * @method getPosX
20237          * @param el the element for which to get the position
20238          * @return {int} the X coordinate
20239          * @for DragDropMgr
20240          * @deprecated use Roo.lib.Dom.getX instead
20241          * @static
20242          */
20243         getPosX: function(el) {
20244             return Roo.lib.Dom.getX(el);
20245         },
20246
20247         /**
20248          * Returns the Y position of an html element
20249          * @method getPosY
20250          * @param el the element for which to get the position
20251          * @return {int} the Y coordinate
20252          * @deprecated use Roo.lib.Dom.getY instead
20253          * @static
20254          */
20255         getPosY: function(el) {
20256             return Roo.lib.Dom.getY(el);
20257         },
20258
20259         /**
20260          * Swap two nodes.  In IE, we use the native method, for others we
20261          * emulate the IE behavior
20262          * @method swapNode
20263          * @param n1 the first node to swap
20264          * @param n2 the other node to swap
20265          * @static
20266          */
20267         swapNode: function(n1, n2) {
20268             if (n1.swapNode) {
20269                 n1.swapNode(n2);
20270             } else {
20271                 var p = n2.parentNode;
20272                 var s = n2.nextSibling;
20273
20274                 if (s == n1) {
20275                     p.insertBefore(n1, n2);
20276                 } else if (n2 == n1.nextSibling) {
20277                     p.insertBefore(n2, n1);
20278                 } else {
20279                     n1.parentNode.replaceChild(n2, n1);
20280                     p.insertBefore(n1, s);
20281                 }
20282             }
20283         },
20284
20285         /**
20286          * Returns the current scroll position
20287          * @method getScroll
20288          * @private
20289          * @static
20290          */
20291         getScroll: function () {
20292             var t, l, dde=document.documentElement, db=document.body;
20293             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20294                 t = dde.scrollTop;
20295                 l = dde.scrollLeft;
20296             } else if (db) {
20297                 t = db.scrollTop;
20298                 l = db.scrollLeft;
20299             } else {
20300
20301             }
20302             return { top: t, left: l };
20303         },
20304
20305         /**
20306          * Returns the specified element style property
20307          * @method getStyle
20308          * @param {HTMLElement} el          the element
20309          * @param {string}      styleProp   the style property
20310          * @return {string} The value of the style property
20311          * @deprecated use Roo.lib.Dom.getStyle
20312          * @static
20313          */
20314         getStyle: function(el, styleProp) {
20315             return Roo.fly(el).getStyle(styleProp);
20316         },
20317
20318         /**
20319          * Gets the scrollTop
20320          * @method getScrollTop
20321          * @return {int} the document's scrollTop
20322          * @static
20323          */
20324         getScrollTop: function () { return this.getScroll().top; },
20325
20326         /**
20327          * Gets the scrollLeft
20328          * @method getScrollLeft
20329          * @return {int} the document's scrollTop
20330          * @static
20331          */
20332         getScrollLeft: function () { return this.getScroll().left; },
20333
20334         /**
20335          * Sets the x/y position of an element to the location of the
20336          * target element.
20337          * @method moveToEl
20338          * @param {HTMLElement} moveEl      The element to move
20339          * @param {HTMLElement} targetEl    The position reference element
20340          * @static
20341          */
20342         moveToEl: function (moveEl, targetEl) {
20343             var aCoord = Roo.lib.Dom.getXY(targetEl);
20344             Roo.lib.Dom.setXY(moveEl, aCoord);
20345         },
20346
20347         /**
20348          * Numeric array sort function
20349          * @method numericSort
20350          * @static
20351          */
20352         numericSort: function(a, b) { return (a - b); },
20353
20354         /**
20355          * Internal counter
20356          * @property _timeoutCount
20357          * @private
20358          * @static
20359          */
20360         _timeoutCount: 0,
20361
20362         /**
20363          * Trying to make the load order less important.  Without this we get
20364          * an error if this file is loaded before the Event Utility.
20365          * @method _addListeners
20366          * @private
20367          * @static
20368          */
20369         _addListeners: function() {
20370             var DDM = Roo.dd.DDM;
20371             if ( Roo.lib.Event && document ) {
20372                 DDM._onLoad();
20373             } else {
20374                 if (DDM._timeoutCount > 2000) {
20375                 } else {
20376                     setTimeout(DDM._addListeners, 10);
20377                     if (document && document.body) {
20378                         DDM._timeoutCount += 1;
20379                     }
20380                 }
20381             }
20382         },
20383
20384         /**
20385          * Recursively searches the immediate parent and all child nodes for
20386          * the handle element in order to determine wheter or not it was
20387          * clicked.
20388          * @method handleWasClicked
20389          * @param node the html element to inspect
20390          * @static
20391          */
20392         handleWasClicked: function(node, id) {
20393             if (this.isHandle(id, node.id)) {
20394                 return true;
20395             } else {
20396                 // check to see if this is a text node child of the one we want
20397                 var p = node.parentNode;
20398
20399                 while (p) {
20400                     if (this.isHandle(id, p.id)) {
20401                         return true;
20402                     } else {
20403                         p = p.parentNode;
20404                     }
20405                 }
20406             }
20407
20408             return false;
20409         }
20410
20411     };
20412
20413 }();
20414
20415 // shorter alias, save a few bytes
20416 Roo.dd.DDM = Roo.dd.DragDropMgr;
20417 Roo.dd.DDM._addListeners();
20418
20419 }/*
20420  * Based on:
20421  * Ext JS Library 1.1.1
20422  * Copyright(c) 2006-2007, Ext JS, LLC.
20423  *
20424  * Originally Released Under LGPL - original licence link has changed is not relivant.
20425  *
20426  * Fork - LGPL
20427  * <script type="text/javascript">
20428  */
20429
20430 /**
20431  * @class Roo.dd.DD
20432  * A DragDrop implementation where the linked element follows the
20433  * mouse cursor during a drag.
20434  * @extends Roo.dd.DragDrop
20435  * @constructor
20436  * @param {String} id the id of the linked element
20437  * @param {String} sGroup the group of related DragDrop items
20438  * @param {object} config an object containing configurable attributes
20439  *                Valid properties for DD:
20440  *                    scroll
20441  */
20442 Roo.dd.DD = function(id, sGroup, config) {
20443     if (id) {
20444         this.init(id, sGroup, config);
20445     }
20446 };
20447
20448 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20449
20450     /**
20451      * When set to true, the utility automatically tries to scroll the browser
20452      * window wehn a drag and drop element is dragged near the viewport boundary.
20453      * Defaults to true.
20454      * @property scroll
20455      * @type boolean
20456      */
20457     scroll: true,
20458
20459     /**
20460      * Sets the pointer offset to the distance between the linked element's top
20461      * left corner and the location the element was clicked
20462      * @method autoOffset
20463      * @param {int} iPageX the X coordinate of the click
20464      * @param {int} iPageY the Y coordinate of the click
20465      */
20466     autoOffset: function(iPageX, iPageY) {
20467         var x = iPageX - this.startPageX;
20468         var y = iPageY - this.startPageY;
20469         this.setDelta(x, y);
20470     },
20471
20472     /**
20473      * Sets the pointer offset.  You can call this directly to force the
20474      * offset to be in a particular location (e.g., pass in 0,0 to set it
20475      * to the center of the object)
20476      * @method setDelta
20477      * @param {int} iDeltaX the distance from the left
20478      * @param {int} iDeltaY the distance from the top
20479      */
20480     setDelta: function(iDeltaX, iDeltaY) {
20481         this.deltaX = iDeltaX;
20482         this.deltaY = iDeltaY;
20483     },
20484
20485     /**
20486      * Sets the drag element to the location of the mousedown or click event,
20487      * maintaining the cursor location relative to the location on the element
20488      * that was clicked.  Override this if you want to place the element in a
20489      * location other than where the cursor is.
20490      * @method setDragElPos
20491      * @param {int} iPageX the X coordinate of the mousedown or drag event
20492      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20493      */
20494     setDragElPos: function(iPageX, iPageY) {
20495         // the first time we do this, we are going to check to make sure
20496         // the element has css positioning
20497
20498         var el = this.getDragEl();
20499         this.alignElWithMouse(el, iPageX, iPageY);
20500     },
20501
20502     /**
20503      * Sets the element to the location of the mousedown or click event,
20504      * maintaining the cursor location relative to the location on the element
20505      * that was clicked.  Override this if you want to place the element in a
20506      * location other than where the cursor is.
20507      * @method alignElWithMouse
20508      * @param {HTMLElement} el the element to move
20509      * @param {int} iPageX the X coordinate of the mousedown or drag event
20510      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20511      */
20512     alignElWithMouse: function(el, iPageX, iPageY) {
20513         var oCoord = this.getTargetCoord(iPageX, iPageY);
20514         var fly = el.dom ? el : Roo.fly(el);
20515         if (!this.deltaSetXY) {
20516             var aCoord = [oCoord.x, oCoord.y];
20517             fly.setXY(aCoord);
20518             var newLeft = fly.getLeft(true);
20519             var newTop  = fly.getTop(true);
20520             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20521         } else {
20522             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20523         }
20524
20525         this.cachePosition(oCoord.x, oCoord.y);
20526         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20527         return oCoord;
20528     },
20529
20530     /**
20531      * Saves the most recent position so that we can reset the constraints and
20532      * tick marks on-demand.  We need to know this so that we can calculate the
20533      * number of pixels the element is offset from its original position.
20534      * @method cachePosition
20535      * @param iPageX the current x position (optional, this just makes it so we
20536      * don't have to look it up again)
20537      * @param iPageY the current y position (optional, this just makes it so we
20538      * don't have to look it up again)
20539      */
20540     cachePosition: function(iPageX, iPageY) {
20541         if (iPageX) {
20542             this.lastPageX = iPageX;
20543             this.lastPageY = iPageY;
20544         } else {
20545             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20546             this.lastPageX = aCoord[0];
20547             this.lastPageY = aCoord[1];
20548         }
20549     },
20550
20551     /**
20552      * Auto-scroll the window if the dragged object has been moved beyond the
20553      * visible window boundary.
20554      * @method autoScroll
20555      * @param {int} x the drag element's x position
20556      * @param {int} y the drag element's y position
20557      * @param {int} h the height of the drag element
20558      * @param {int} w the width of the drag element
20559      * @private
20560      */
20561     autoScroll: function(x, y, h, w) {
20562
20563         if (this.scroll) {
20564             // The client height
20565             var clientH = Roo.lib.Dom.getViewWidth();
20566
20567             // The client width
20568             var clientW = Roo.lib.Dom.getViewHeight();
20569
20570             // The amt scrolled down
20571             var st = this.DDM.getScrollTop();
20572
20573             // The amt scrolled right
20574             var sl = this.DDM.getScrollLeft();
20575
20576             // Location of the bottom of the element
20577             var bot = h + y;
20578
20579             // Location of the right of the element
20580             var right = w + x;
20581
20582             // The distance from the cursor to the bottom of the visible area,
20583             // adjusted so that we don't scroll if the cursor is beyond the
20584             // element drag constraints
20585             var toBot = (clientH + st - y - this.deltaY);
20586
20587             // The distance from the cursor to the right of the visible area
20588             var toRight = (clientW + sl - x - this.deltaX);
20589
20590
20591             // How close to the edge the cursor must be before we scroll
20592             // var thresh = (document.all) ? 100 : 40;
20593             var thresh = 40;
20594
20595             // How many pixels to scroll per autoscroll op.  This helps to reduce
20596             // clunky scrolling. IE is more sensitive about this ... it needs this
20597             // value to be higher.
20598             var scrAmt = (document.all) ? 80 : 30;
20599
20600             // Scroll down if we are near the bottom of the visible page and the
20601             // obj extends below the crease
20602             if ( bot > clientH && toBot < thresh ) {
20603                 window.scrollTo(sl, st + scrAmt);
20604             }
20605
20606             // Scroll up if the window is scrolled down and the top of the object
20607             // goes above the top border
20608             if ( y < st && st > 0 && y - st < thresh ) {
20609                 window.scrollTo(sl, st - scrAmt);
20610             }
20611
20612             // Scroll right if the obj is beyond the right border and the cursor is
20613             // near the border.
20614             if ( right > clientW && toRight < thresh ) {
20615                 window.scrollTo(sl + scrAmt, st);
20616             }
20617
20618             // Scroll left if the window has been scrolled to the right and the obj
20619             // extends past the left border
20620             if ( x < sl && sl > 0 && x - sl < thresh ) {
20621                 window.scrollTo(sl - scrAmt, st);
20622             }
20623         }
20624     },
20625
20626     /**
20627      * Finds the location the element should be placed if we want to move
20628      * it to where the mouse location less the click offset would place us.
20629      * @method getTargetCoord
20630      * @param {int} iPageX the X coordinate of the click
20631      * @param {int} iPageY the Y coordinate of the click
20632      * @return an object that contains the coordinates (Object.x and Object.y)
20633      * @private
20634      */
20635     getTargetCoord: function(iPageX, iPageY) {
20636
20637
20638         var x = iPageX - this.deltaX;
20639         var y = iPageY - this.deltaY;
20640
20641         if (this.constrainX) {
20642             if (x < this.minX) { x = this.minX; }
20643             if (x > this.maxX) { x = this.maxX; }
20644         }
20645
20646         if (this.constrainY) {
20647             if (y < this.minY) { y = this.minY; }
20648             if (y > this.maxY) { y = this.maxY; }
20649         }
20650
20651         x = this.getTick(x, this.xTicks);
20652         y = this.getTick(y, this.yTicks);
20653
20654
20655         return {x:x, y:y};
20656     },
20657
20658     /*
20659      * Sets up config options specific to this class. Overrides
20660      * Roo.dd.DragDrop, but all versions of this method through the
20661      * inheritance chain are called
20662      */
20663     applyConfig: function() {
20664         Roo.dd.DD.superclass.applyConfig.call(this);
20665         this.scroll = (this.config.scroll !== false);
20666     },
20667
20668     /*
20669      * Event that fires prior to the onMouseDown event.  Overrides
20670      * Roo.dd.DragDrop.
20671      */
20672     b4MouseDown: function(e) {
20673         // this.resetConstraints();
20674         this.autoOffset(e.getPageX(),
20675                             e.getPageY());
20676     },
20677
20678     /*
20679      * Event that fires prior to the onDrag event.  Overrides
20680      * Roo.dd.DragDrop.
20681      */
20682     b4Drag: function(e) {
20683         this.setDragElPos(e.getPageX(),
20684                             e.getPageY());
20685     },
20686
20687     toString: function() {
20688         return ("DD " + this.id);
20689     }
20690
20691     //////////////////////////////////////////////////////////////////////////
20692     // Debugging ygDragDrop events that can be overridden
20693     //////////////////////////////////////////////////////////////////////////
20694     /*
20695     startDrag: function(x, y) {
20696     },
20697
20698     onDrag: function(e) {
20699     },
20700
20701     onDragEnter: function(e, id) {
20702     },
20703
20704     onDragOver: function(e, id) {
20705     },
20706
20707     onDragOut: function(e, id) {
20708     },
20709
20710     onDragDrop: function(e, id) {
20711     },
20712
20713     endDrag: function(e) {
20714     }
20715
20716     */
20717
20718 });/*
20719  * Based on:
20720  * Ext JS Library 1.1.1
20721  * Copyright(c) 2006-2007, Ext JS, LLC.
20722  *
20723  * Originally Released Under LGPL - original licence link has changed is not relivant.
20724  *
20725  * Fork - LGPL
20726  * <script type="text/javascript">
20727  */
20728
20729 /**
20730  * @class Roo.dd.DDProxy
20731  * A DragDrop implementation that inserts an empty, bordered div into
20732  * the document that follows the cursor during drag operations.  At the time of
20733  * the click, the frame div is resized to the dimensions of the linked html
20734  * element, and moved to the exact location of the linked element.
20735  *
20736  * References to the "frame" element refer to the single proxy element that
20737  * was created to be dragged in place of all DDProxy elements on the
20738  * page.
20739  *
20740  * @extends Roo.dd.DD
20741  * @constructor
20742  * @param {String} id the id of the linked html element
20743  * @param {String} sGroup the group of related DragDrop objects
20744  * @param {object} config an object containing configurable attributes
20745  *                Valid properties for DDProxy in addition to those in DragDrop:
20746  *                   resizeFrame, centerFrame, dragElId
20747  */
20748 Roo.dd.DDProxy = function(id, sGroup, config) {
20749     if (id) {
20750         this.init(id, sGroup, config);
20751         this.initFrame();
20752     }
20753 };
20754
20755 /**
20756  * The default drag frame div id
20757  * @property Roo.dd.DDProxy.dragElId
20758  * @type String
20759  * @static
20760  */
20761 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20762
20763 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20764
20765     /**
20766      * By default we resize the drag frame to be the same size as the element
20767      * we want to drag (this is to get the frame effect).  We can turn it off
20768      * if we want a different behavior.
20769      * @property resizeFrame
20770      * @type boolean
20771      */
20772     resizeFrame: true,
20773
20774     /**
20775      * By default the frame is positioned exactly where the drag element is, so
20776      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20777      * you do not have constraints on the obj is to have the drag frame centered
20778      * around the cursor.  Set centerFrame to true for this effect.
20779      * @property centerFrame
20780      * @type boolean
20781      */
20782     centerFrame: false,
20783
20784     /**
20785      * Creates the proxy element if it does not yet exist
20786      * @method createFrame
20787      */
20788     createFrame: function() {
20789         var self = this;
20790         var body = document.body;
20791
20792         if (!body || !body.firstChild) {
20793             setTimeout( function() { self.createFrame(); }, 50 );
20794             return;
20795         }
20796
20797         var div = this.getDragEl();
20798
20799         if (!div) {
20800             div    = document.createElement("div");
20801             div.id = this.dragElId;
20802             var s  = div.style;
20803
20804             s.position   = "absolute";
20805             s.visibility = "hidden";
20806             s.cursor     = "move";
20807             s.border     = "2px solid #aaa";
20808             s.zIndex     = 999;
20809
20810             // appendChild can blow up IE if invoked prior to the window load event
20811             // while rendering a table.  It is possible there are other scenarios
20812             // that would cause this to happen as well.
20813             body.insertBefore(div, body.firstChild);
20814         }
20815     },
20816
20817     /**
20818      * Initialization for the drag frame element.  Must be called in the
20819      * constructor of all subclasses
20820      * @method initFrame
20821      */
20822     initFrame: function() {
20823         this.createFrame();
20824     },
20825
20826     applyConfig: function() {
20827         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20828
20829         this.resizeFrame = (this.config.resizeFrame !== false);
20830         this.centerFrame = (this.config.centerFrame);
20831         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20832     },
20833
20834     /**
20835      * Resizes the drag frame to the dimensions of the clicked object, positions
20836      * it over the object, and finally displays it
20837      * @method showFrame
20838      * @param {int} iPageX X click position
20839      * @param {int} iPageY Y click position
20840      * @private
20841      */
20842     showFrame: function(iPageX, iPageY) {
20843         var el = this.getEl();
20844         var dragEl = this.getDragEl();
20845         var s = dragEl.style;
20846
20847         this._resizeProxy();
20848
20849         if (this.centerFrame) {
20850             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20851                            Math.round(parseInt(s.height, 10)/2) );
20852         }
20853
20854         this.setDragElPos(iPageX, iPageY);
20855
20856         Roo.fly(dragEl).show();
20857     },
20858
20859     /**
20860      * The proxy is automatically resized to the dimensions of the linked
20861      * element when a drag is initiated, unless resizeFrame is set to false
20862      * @method _resizeProxy
20863      * @private
20864      */
20865     _resizeProxy: function() {
20866         if (this.resizeFrame) {
20867             var el = this.getEl();
20868             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20869         }
20870     },
20871
20872     // overrides Roo.dd.DragDrop
20873     b4MouseDown: function(e) {
20874         var x = e.getPageX();
20875         var y = e.getPageY();
20876         this.autoOffset(x, y);
20877         this.setDragElPos(x, y);
20878     },
20879
20880     // overrides Roo.dd.DragDrop
20881     b4StartDrag: function(x, y) {
20882         // show the drag frame
20883         this.showFrame(x, y);
20884     },
20885
20886     // overrides Roo.dd.DragDrop
20887     b4EndDrag: function(e) {
20888         Roo.fly(this.getDragEl()).hide();
20889     },
20890
20891     // overrides Roo.dd.DragDrop
20892     // By default we try to move the element to the last location of the frame.
20893     // This is so that the default behavior mirrors that of Roo.dd.DD.
20894     endDrag: function(e) {
20895
20896         var lel = this.getEl();
20897         var del = this.getDragEl();
20898
20899         // Show the drag frame briefly so we can get its position
20900         del.style.visibility = "";
20901
20902         this.beforeMove();
20903         // Hide the linked element before the move to get around a Safari
20904         // rendering bug.
20905         lel.style.visibility = "hidden";
20906         Roo.dd.DDM.moveToEl(lel, del);
20907         del.style.visibility = "hidden";
20908         lel.style.visibility = "";
20909
20910         this.afterDrag();
20911     },
20912
20913     beforeMove : function(){
20914
20915     },
20916
20917     afterDrag : function(){
20918
20919     },
20920
20921     toString: function() {
20922         return ("DDProxy " + this.id);
20923     }
20924
20925 });
20926 /*
20927  * Based on:
20928  * Ext JS Library 1.1.1
20929  * Copyright(c) 2006-2007, Ext JS, LLC.
20930  *
20931  * Originally Released Under LGPL - original licence link has changed is not relivant.
20932  *
20933  * Fork - LGPL
20934  * <script type="text/javascript">
20935  */
20936
20937  /**
20938  * @class Roo.dd.DDTarget
20939  * A DragDrop implementation that does not move, but can be a drop
20940  * target.  You would get the same result by simply omitting implementation
20941  * for the event callbacks, but this way we reduce the processing cost of the
20942  * event listener and the callbacks.
20943  * @extends Roo.dd.DragDrop
20944  * @constructor
20945  * @param {String} id the id of the element that is a drop target
20946  * @param {String} sGroup the group of related DragDrop objects
20947  * @param {object} config an object containing configurable attributes
20948  *                 Valid properties for DDTarget in addition to those in
20949  *                 DragDrop:
20950  *                    none
20951  */
20952 Roo.dd.DDTarget = function(id, sGroup, config) {
20953     if (id) {
20954         this.initTarget(id, sGroup, config);
20955     }
20956     if (config.listeners || config.events) { 
20957        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20958             listeners : config.listeners || {}, 
20959             events : config.events || {} 
20960         });    
20961     }
20962 };
20963
20964 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20965 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20966     toString: function() {
20967         return ("DDTarget " + this.id);
20968     }
20969 });
20970 /*
20971  * Based on:
20972  * Ext JS Library 1.1.1
20973  * Copyright(c) 2006-2007, Ext JS, LLC.
20974  *
20975  * Originally Released Under LGPL - original licence link has changed is not relivant.
20976  *
20977  * Fork - LGPL
20978  * <script type="text/javascript">
20979  */
20980  
20981
20982 /**
20983  * @class Roo.dd.ScrollManager
20984  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20985  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20986  * @singleton
20987  */
20988 Roo.dd.ScrollManager = function(){
20989     var ddm = Roo.dd.DragDropMgr;
20990     var els = {};
20991     var dragEl = null;
20992     var proc = {};
20993     
20994     
20995     
20996     var onStop = function(e){
20997         dragEl = null;
20998         clearProc();
20999     };
21000     
21001     var triggerRefresh = function(){
21002         if(ddm.dragCurrent){
21003              ddm.refreshCache(ddm.dragCurrent.groups);
21004         }
21005     };
21006     
21007     var doScroll = function(){
21008         if(ddm.dragCurrent){
21009             var dds = Roo.dd.ScrollManager;
21010             if(!dds.animate){
21011                 if(proc.el.scroll(proc.dir, dds.increment)){
21012                     triggerRefresh();
21013                 }
21014             }else{
21015                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21016             }
21017         }
21018     };
21019     
21020     var clearProc = function(){
21021         if(proc.id){
21022             clearInterval(proc.id);
21023         }
21024         proc.id = 0;
21025         proc.el = null;
21026         proc.dir = "";
21027     };
21028     
21029     var startProc = function(el, dir){
21030          Roo.log('scroll startproc');
21031         clearProc();
21032         proc.el = el;
21033         proc.dir = dir;
21034         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21035     };
21036     
21037     var onFire = function(e, isDrop){
21038        
21039         if(isDrop || !ddm.dragCurrent){ return; }
21040         var dds = Roo.dd.ScrollManager;
21041         if(!dragEl || dragEl != ddm.dragCurrent){
21042             dragEl = ddm.dragCurrent;
21043             // refresh regions on drag start
21044             dds.refreshCache();
21045         }
21046         
21047         var xy = Roo.lib.Event.getXY(e);
21048         var pt = new Roo.lib.Point(xy[0], xy[1]);
21049         for(var id in els){
21050             var el = els[id], r = el._region;
21051             if(r && r.contains(pt) && el.isScrollable()){
21052                 if(r.bottom - pt.y <= dds.thresh){
21053                     if(proc.el != el){
21054                         startProc(el, "down");
21055                     }
21056                     return;
21057                 }else if(r.right - pt.x <= dds.thresh){
21058                     if(proc.el != el){
21059                         startProc(el, "left");
21060                     }
21061                     return;
21062                 }else if(pt.y - r.top <= dds.thresh){
21063                     if(proc.el != el){
21064                         startProc(el, "up");
21065                     }
21066                     return;
21067                 }else if(pt.x - r.left <= dds.thresh){
21068                     if(proc.el != el){
21069                         startProc(el, "right");
21070                     }
21071                     return;
21072                 }
21073             }
21074         }
21075         clearProc();
21076     };
21077     
21078     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21079     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21080     
21081     return {
21082         /**
21083          * Registers new overflow element(s) to auto scroll
21084          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21085          */
21086         register : function(el){
21087             if(el instanceof Array){
21088                 for(var i = 0, len = el.length; i < len; i++) {
21089                         this.register(el[i]);
21090                 }
21091             }else{
21092                 el = Roo.get(el);
21093                 els[el.id] = el;
21094             }
21095             Roo.dd.ScrollManager.els = els;
21096         },
21097         
21098         /**
21099          * Unregisters overflow element(s) so they are no longer scrolled
21100          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21101          */
21102         unregister : function(el){
21103             if(el instanceof Array){
21104                 for(var i = 0, len = el.length; i < len; i++) {
21105                         this.unregister(el[i]);
21106                 }
21107             }else{
21108                 el = Roo.get(el);
21109                 delete els[el.id];
21110             }
21111         },
21112         
21113         /**
21114          * The number of pixels from the edge of a container the pointer needs to be to 
21115          * trigger scrolling (defaults to 25)
21116          * @type Number
21117          */
21118         thresh : 25,
21119         
21120         /**
21121          * The number of pixels to scroll in each scroll increment (defaults to 50)
21122          * @type Number
21123          */
21124         increment : 100,
21125         
21126         /**
21127          * The frequency of scrolls in milliseconds (defaults to 500)
21128          * @type Number
21129          */
21130         frequency : 500,
21131         
21132         /**
21133          * True to animate the scroll (defaults to true)
21134          * @type Boolean
21135          */
21136         animate: true,
21137         
21138         /**
21139          * The animation duration in seconds - 
21140          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21141          * @type Number
21142          */
21143         animDuration: .4,
21144         
21145         /**
21146          * Manually trigger a cache refresh.
21147          */
21148         refreshCache : function(){
21149             for(var id in els){
21150                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21151                     els[id]._region = els[id].getRegion();
21152                 }
21153             }
21154         }
21155     };
21156 }();/*
21157  * Based on:
21158  * Ext JS Library 1.1.1
21159  * Copyright(c) 2006-2007, Ext JS, LLC.
21160  *
21161  * Originally Released Under LGPL - original licence link has changed is not relivant.
21162  *
21163  * Fork - LGPL
21164  * <script type="text/javascript">
21165  */
21166  
21167
21168 /**
21169  * @class Roo.dd.Registry
21170  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21171  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21172  * @singleton
21173  */
21174 Roo.dd.Registry = function(){
21175     var elements = {}; 
21176     var handles = {}; 
21177     var autoIdSeed = 0;
21178
21179     var getId = function(el, autogen){
21180         if(typeof el == "string"){
21181             return el;
21182         }
21183         var id = el.id;
21184         if(!id && autogen !== false){
21185             id = "roodd-" + (++autoIdSeed);
21186             el.id = id;
21187         }
21188         return id;
21189     };
21190     
21191     return {
21192     /**
21193      * Register a drag drop element
21194      * @param {String|HTMLElement} element The id or DOM node to register
21195      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21196      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21197      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21198      * populated in the data object (if applicable):
21199      * <pre>
21200 Value      Description<br />
21201 ---------  ------------------------------------------<br />
21202 handles    Array of DOM nodes that trigger dragging<br />
21203            for the element being registered<br />
21204 isHandle   True if the element passed in triggers<br />
21205            dragging itself, else false
21206 </pre>
21207      */
21208         register : function(el, data){
21209             data = data || {};
21210             if(typeof el == "string"){
21211                 el = document.getElementById(el);
21212             }
21213             data.ddel = el;
21214             elements[getId(el)] = data;
21215             if(data.isHandle !== false){
21216                 handles[data.ddel.id] = data;
21217             }
21218             if(data.handles){
21219                 var hs = data.handles;
21220                 for(var i = 0, len = hs.length; i < len; i++){
21221                         handles[getId(hs[i])] = data;
21222                 }
21223             }
21224         },
21225
21226     /**
21227      * Unregister a drag drop element
21228      * @param {String|HTMLElement}  element The id or DOM node to unregister
21229      */
21230         unregister : function(el){
21231             var id = getId(el, false);
21232             var data = elements[id];
21233             if(data){
21234                 delete elements[id];
21235                 if(data.handles){
21236                     var hs = data.handles;
21237                     for(var i = 0, len = hs.length; i < len; i++){
21238                         delete handles[getId(hs[i], false)];
21239                     }
21240                 }
21241             }
21242         },
21243
21244     /**
21245      * Returns the handle registered for a DOM Node by id
21246      * @param {String|HTMLElement} id The DOM node or id to look up
21247      * @return {Object} handle The custom handle data
21248      */
21249         getHandle : function(id){
21250             if(typeof id != "string"){ // must be element?
21251                 id = id.id;
21252             }
21253             return handles[id];
21254         },
21255
21256     /**
21257      * Returns the handle that is registered for the DOM node that is the target of the event
21258      * @param {Event} e The event
21259      * @return {Object} handle The custom handle data
21260      */
21261         getHandleFromEvent : function(e){
21262             var t = Roo.lib.Event.getTarget(e);
21263             return t ? handles[t.id] : null;
21264         },
21265
21266     /**
21267      * Returns a custom data object that is registered for a DOM node by id
21268      * @param {String|HTMLElement} id The DOM node or id to look up
21269      * @return {Object} data The custom data
21270      */
21271         getTarget : function(id){
21272             if(typeof id != "string"){ // must be element?
21273                 id = id.id;
21274             }
21275             return elements[id];
21276         },
21277
21278     /**
21279      * Returns a custom data object that is registered for the DOM node that is the target of the event
21280      * @param {Event} e The event
21281      * @return {Object} data The custom data
21282      */
21283         getTargetFromEvent : function(e){
21284             var t = Roo.lib.Event.getTarget(e);
21285             return t ? elements[t.id] || handles[t.id] : null;
21286         }
21287     };
21288 }();/*
21289  * Based on:
21290  * Ext JS Library 1.1.1
21291  * Copyright(c) 2006-2007, Ext JS, LLC.
21292  *
21293  * Originally Released Under LGPL - original licence link has changed is not relivant.
21294  *
21295  * Fork - LGPL
21296  * <script type="text/javascript">
21297  */
21298  
21299
21300 /**
21301  * @class Roo.dd.StatusProxy
21302  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21303  * default drag proxy used by all Roo.dd components.
21304  * @constructor
21305  * @param {Object} config
21306  */
21307 Roo.dd.StatusProxy = function(config){
21308     Roo.apply(this, config);
21309     this.id = this.id || Roo.id();
21310     this.el = new Roo.Layer({
21311         dh: {
21312             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21313                 {tag: "div", cls: "x-dd-drop-icon"},
21314                 {tag: "div", cls: "x-dd-drag-ghost"}
21315             ]
21316         }, 
21317         shadow: !config || config.shadow !== false
21318     });
21319     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21320     this.dropStatus = this.dropNotAllowed;
21321 };
21322
21323 Roo.dd.StatusProxy.prototype = {
21324     /**
21325      * @cfg {String} dropAllowed
21326      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21327      */
21328     dropAllowed : "x-dd-drop-ok",
21329     /**
21330      * @cfg {String} dropNotAllowed
21331      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21332      */
21333     dropNotAllowed : "x-dd-drop-nodrop",
21334
21335     /**
21336      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21337      * over the current target element.
21338      * @param {String} cssClass The css class for the new drop status indicator image
21339      */
21340     setStatus : function(cssClass){
21341         cssClass = cssClass || this.dropNotAllowed;
21342         if(this.dropStatus != cssClass){
21343             this.el.replaceClass(this.dropStatus, cssClass);
21344             this.dropStatus = cssClass;
21345         }
21346     },
21347
21348     /**
21349      * Resets the status indicator to the default dropNotAllowed value
21350      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21351      */
21352     reset : function(clearGhost){
21353         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21354         this.dropStatus = this.dropNotAllowed;
21355         if(clearGhost){
21356             this.ghost.update("");
21357         }
21358     },
21359
21360     /**
21361      * Updates the contents of the ghost element
21362      * @param {String} html The html that will replace the current innerHTML of the ghost element
21363      */
21364     update : function(html){
21365         if(typeof html == "string"){
21366             this.ghost.update(html);
21367         }else{
21368             this.ghost.update("");
21369             html.style.margin = "0";
21370             this.ghost.dom.appendChild(html);
21371         }
21372         // ensure float = none set?? cant remember why though.
21373         var el = this.ghost.dom.firstChild;
21374                 if(el){
21375                         Roo.fly(el).setStyle('float', 'none');
21376                 }
21377     },
21378     
21379     /**
21380      * Returns the underlying proxy {@link Roo.Layer}
21381      * @return {Roo.Layer} el
21382     */
21383     getEl : function(){
21384         return this.el;
21385     },
21386
21387     /**
21388      * Returns the ghost element
21389      * @return {Roo.Element} el
21390      */
21391     getGhost : function(){
21392         return this.ghost;
21393     },
21394
21395     /**
21396      * Hides the proxy
21397      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21398      */
21399     hide : function(clear){
21400         this.el.hide();
21401         if(clear){
21402             this.reset(true);
21403         }
21404     },
21405
21406     /**
21407      * Stops the repair animation if it's currently running
21408      */
21409     stop : function(){
21410         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21411             this.anim.stop();
21412         }
21413     },
21414
21415     /**
21416      * Displays this proxy
21417      */
21418     show : function(){
21419         this.el.show();
21420     },
21421
21422     /**
21423      * Force the Layer to sync its shadow and shim positions to the element
21424      */
21425     sync : function(){
21426         this.el.sync();
21427     },
21428
21429     /**
21430      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21431      * invalid drop operation by the item being dragged.
21432      * @param {Array} xy The XY position of the element ([x, y])
21433      * @param {Function} callback The function to call after the repair is complete
21434      * @param {Object} scope The scope in which to execute the callback
21435      */
21436     repair : function(xy, callback, scope){
21437         this.callback = callback;
21438         this.scope = scope;
21439         if(xy && this.animRepair !== false){
21440             this.el.addClass("x-dd-drag-repair");
21441             this.el.hideUnders(true);
21442             this.anim = this.el.shift({
21443                 duration: this.repairDuration || .5,
21444                 easing: 'easeOut',
21445                 xy: xy,
21446                 stopFx: true,
21447                 callback: this.afterRepair,
21448                 scope: this
21449             });
21450         }else{
21451             this.afterRepair();
21452         }
21453     },
21454
21455     // private
21456     afterRepair : function(){
21457         this.hide(true);
21458         if(typeof this.callback == "function"){
21459             this.callback.call(this.scope || this);
21460         }
21461         this.callback = null;
21462         this.scope = null;
21463     }
21464 };/*
21465  * Based on:
21466  * Ext JS Library 1.1.1
21467  * Copyright(c) 2006-2007, Ext JS, LLC.
21468  *
21469  * Originally Released Under LGPL - original licence link has changed is not relivant.
21470  *
21471  * Fork - LGPL
21472  * <script type="text/javascript">
21473  */
21474
21475 /**
21476  * @class Roo.dd.DragSource
21477  * @extends Roo.dd.DDProxy
21478  * A simple class that provides the basic implementation needed to make any element draggable.
21479  * @constructor
21480  * @param {String/HTMLElement/Element} el The container element
21481  * @param {Object} config
21482  */
21483 Roo.dd.DragSource = function(el, config){
21484     this.el = Roo.get(el);
21485     this.dragData = {};
21486     
21487     Roo.apply(this, config);
21488     
21489     if(!this.proxy){
21490         this.proxy = new Roo.dd.StatusProxy();
21491     }
21492
21493     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21494           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21495     
21496     this.dragging = false;
21497 };
21498
21499 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21500     /**
21501      * @cfg {String} dropAllowed
21502      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21503      */
21504     dropAllowed : "x-dd-drop-ok",
21505     /**
21506      * @cfg {String} dropNotAllowed
21507      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21508      */
21509     dropNotAllowed : "x-dd-drop-nodrop",
21510
21511     /**
21512      * Returns the data object associated with this drag source
21513      * @return {Object} data An object containing arbitrary data
21514      */
21515     getDragData : function(e){
21516         return this.dragData;
21517     },
21518
21519     // private
21520     onDragEnter : function(e, id){
21521         var target = Roo.dd.DragDropMgr.getDDById(id);
21522         this.cachedTarget = target;
21523         if(this.beforeDragEnter(target, e, id) !== false){
21524             if(target.isNotifyTarget){
21525                 var status = target.notifyEnter(this, e, this.dragData);
21526                 this.proxy.setStatus(status);
21527             }else{
21528                 this.proxy.setStatus(this.dropAllowed);
21529             }
21530             
21531             if(this.afterDragEnter){
21532                 /**
21533                  * An empty function by default, but provided so that you can perform a custom action
21534                  * when the dragged item enters the drop target by providing an implementation.
21535                  * @param {Roo.dd.DragDrop} target The drop target
21536                  * @param {Event} e The event object
21537                  * @param {String} id The id of the dragged element
21538                  * @method afterDragEnter
21539                  */
21540                 this.afterDragEnter(target, e, id);
21541             }
21542         }
21543     },
21544
21545     /**
21546      * An empty function by default, but provided so that you can perform a custom action
21547      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21548      * @param {Roo.dd.DragDrop} target The drop target
21549      * @param {Event} e The event object
21550      * @param {String} id The id of the dragged element
21551      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21552      */
21553     beforeDragEnter : function(target, e, id){
21554         return true;
21555     },
21556
21557     // private
21558     alignElWithMouse: function() {
21559         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21560         this.proxy.sync();
21561     },
21562
21563     // private
21564     onDragOver : function(e, id){
21565         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21566         if(this.beforeDragOver(target, e, id) !== false){
21567             if(target.isNotifyTarget){
21568                 var status = target.notifyOver(this, e, this.dragData);
21569                 this.proxy.setStatus(status);
21570             }
21571
21572             if(this.afterDragOver){
21573                 /**
21574                  * An empty function by default, but provided so that you can perform a custom action
21575                  * while the dragged item is over the drop target by providing an implementation.
21576                  * @param {Roo.dd.DragDrop} target The drop target
21577                  * @param {Event} e The event object
21578                  * @param {String} id The id of the dragged element
21579                  * @method afterDragOver
21580                  */
21581                 this.afterDragOver(target, e, id);
21582             }
21583         }
21584     },
21585
21586     /**
21587      * An empty function by default, but provided so that you can perform a custom action
21588      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21589      * @param {Roo.dd.DragDrop} target The drop target
21590      * @param {Event} e The event object
21591      * @param {String} id The id of the dragged element
21592      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21593      */
21594     beforeDragOver : function(target, e, id){
21595         return true;
21596     },
21597
21598     // private
21599     onDragOut : function(e, id){
21600         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21601         if(this.beforeDragOut(target, e, id) !== false){
21602             if(target.isNotifyTarget){
21603                 target.notifyOut(this, e, this.dragData);
21604             }
21605             this.proxy.reset();
21606             if(this.afterDragOut){
21607                 /**
21608                  * An empty function by default, but provided so that you can perform a custom action
21609                  * after the dragged item is dragged out of the target without dropping.
21610                  * @param {Roo.dd.DragDrop} target The drop target
21611                  * @param {Event} e The event object
21612                  * @param {String} id The id of the dragged element
21613                  * @method afterDragOut
21614                  */
21615                 this.afterDragOut(target, e, id);
21616             }
21617         }
21618         this.cachedTarget = null;
21619     },
21620
21621     /**
21622      * An empty function by default, but provided so that you can perform a custom action before the dragged
21623      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21624      * @param {Roo.dd.DragDrop} target The drop target
21625      * @param {Event} e The event object
21626      * @param {String} id The id of the dragged element
21627      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21628      */
21629     beforeDragOut : function(target, e, id){
21630         return true;
21631     },
21632     
21633     // private
21634     onDragDrop : function(e, id){
21635         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21636         if(this.beforeDragDrop(target, e, id) !== false){
21637             if(target.isNotifyTarget){
21638                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21639                     this.onValidDrop(target, e, id);
21640                 }else{
21641                     this.onInvalidDrop(target, e, id);
21642                 }
21643             }else{
21644                 this.onValidDrop(target, e, id);
21645             }
21646             
21647             if(this.afterDragDrop){
21648                 /**
21649                  * An empty function by default, but provided so that you can perform a custom action
21650                  * after a valid drag drop has occurred by providing an implementation.
21651                  * @param {Roo.dd.DragDrop} target The drop target
21652                  * @param {Event} e The event object
21653                  * @param {String} id The id of the dropped element
21654                  * @method afterDragDrop
21655                  */
21656                 this.afterDragDrop(target, e, id);
21657             }
21658         }
21659         delete this.cachedTarget;
21660     },
21661
21662     /**
21663      * An empty function by default, but provided so that you can perform a custom action before the dragged
21664      * item is dropped onto the target and optionally cancel the onDragDrop.
21665      * @param {Roo.dd.DragDrop} target The drop target
21666      * @param {Event} e The event object
21667      * @param {String} id The id of the dragged element
21668      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21669      */
21670     beforeDragDrop : function(target, e, id){
21671         return true;
21672     },
21673
21674     // private
21675     onValidDrop : function(target, e, id){
21676         this.hideProxy();
21677         if(this.afterValidDrop){
21678             /**
21679              * An empty function by default, but provided so that you can perform a custom action
21680              * after a valid drop has occurred by providing an implementation.
21681              * @param {Object} target The target DD 
21682              * @param {Event} e The event object
21683              * @param {String} id The id of the dropped element
21684              * @method afterInvalidDrop
21685              */
21686             this.afterValidDrop(target, e, id);
21687         }
21688     },
21689
21690     // private
21691     getRepairXY : function(e, data){
21692         return this.el.getXY();  
21693     },
21694
21695     // private
21696     onInvalidDrop : function(target, e, id){
21697         this.beforeInvalidDrop(target, e, id);
21698         if(this.cachedTarget){
21699             if(this.cachedTarget.isNotifyTarget){
21700                 this.cachedTarget.notifyOut(this, e, this.dragData);
21701             }
21702             this.cacheTarget = null;
21703         }
21704         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21705
21706         if(this.afterInvalidDrop){
21707             /**
21708              * An empty function by default, but provided so that you can perform a custom action
21709              * after an invalid drop has occurred by providing an implementation.
21710              * @param {Event} e The event object
21711              * @param {String} id The id of the dropped element
21712              * @method afterInvalidDrop
21713              */
21714             this.afterInvalidDrop(e, id);
21715         }
21716     },
21717
21718     // private
21719     afterRepair : function(){
21720         if(Roo.enableFx){
21721             this.el.highlight(this.hlColor || "c3daf9");
21722         }
21723         this.dragging = false;
21724     },
21725
21726     /**
21727      * An empty function by default, but provided so that you can perform a custom action after an invalid
21728      * drop has occurred.
21729      * @param {Roo.dd.DragDrop} target The drop target
21730      * @param {Event} e The event object
21731      * @param {String} id The id of the dragged element
21732      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21733      */
21734     beforeInvalidDrop : function(target, e, id){
21735         return true;
21736     },
21737
21738     // private
21739     handleMouseDown : function(e){
21740         if(this.dragging) {
21741             return;
21742         }
21743         var data = this.getDragData(e);
21744         if(data && this.onBeforeDrag(data, e) !== false){
21745             this.dragData = data;
21746             this.proxy.stop();
21747             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21748         } 
21749     },
21750
21751     /**
21752      * An empty function by default, but provided so that you can perform a custom action before the initial
21753      * drag event begins and optionally cancel it.
21754      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21755      * @param {Event} e The event object
21756      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21757      */
21758     onBeforeDrag : function(data, e){
21759         return true;
21760     },
21761
21762     /**
21763      * An empty function by default, but provided so that you can perform a custom action once the initial
21764      * drag event has begun.  The drag cannot be canceled from this function.
21765      * @param {Number} x The x position of the click on the dragged object
21766      * @param {Number} y The y position of the click on the dragged object
21767      */
21768     onStartDrag : Roo.emptyFn,
21769
21770     // private - YUI override
21771     startDrag : function(x, y){
21772         this.proxy.reset();
21773         this.dragging = true;
21774         this.proxy.update("");
21775         this.onInitDrag(x, y);
21776         this.proxy.show();
21777     },
21778
21779     // private
21780     onInitDrag : function(x, y){
21781         var clone = this.el.dom.cloneNode(true);
21782         clone.id = Roo.id(); // prevent duplicate ids
21783         this.proxy.update(clone);
21784         this.onStartDrag(x, y);
21785         return true;
21786     },
21787
21788     /**
21789      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21790      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21791      */
21792     getProxy : function(){
21793         return this.proxy;  
21794     },
21795
21796     /**
21797      * Hides the drag source's {@link Roo.dd.StatusProxy}
21798      */
21799     hideProxy : function(){
21800         this.proxy.hide();  
21801         this.proxy.reset(true);
21802         this.dragging = false;
21803     },
21804
21805     // private
21806     triggerCacheRefresh : function(){
21807         Roo.dd.DDM.refreshCache(this.groups);
21808     },
21809
21810     // private - override to prevent hiding
21811     b4EndDrag: function(e) {
21812     },
21813
21814     // private - override to prevent moving
21815     endDrag : function(e){
21816         this.onEndDrag(this.dragData, e);
21817     },
21818
21819     // private
21820     onEndDrag : function(data, e){
21821     },
21822     
21823     // private - pin to cursor
21824     autoOffset : function(x, y) {
21825         this.setDelta(-12, -20);
21826     }    
21827 });/*
21828  * Based on:
21829  * Ext JS Library 1.1.1
21830  * Copyright(c) 2006-2007, Ext JS, LLC.
21831  *
21832  * Originally Released Under LGPL - original licence link has changed is not relivant.
21833  *
21834  * Fork - LGPL
21835  * <script type="text/javascript">
21836  */
21837
21838
21839 /**
21840  * @class Roo.dd.DropTarget
21841  * @extends Roo.dd.DDTarget
21842  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21843  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21844  * @constructor
21845  * @param {String/HTMLElement/Element} el The container element
21846  * @param {Object} config
21847  */
21848 Roo.dd.DropTarget = function(el, config){
21849     this.el = Roo.get(el);
21850     
21851     var listeners = false; ;
21852     if (config && config.listeners) {
21853         listeners= config.listeners;
21854         delete config.listeners;
21855     }
21856     Roo.apply(this, config);
21857     
21858     if(this.containerScroll){
21859         Roo.dd.ScrollManager.register(this.el);
21860     }
21861     this.addEvents( {
21862          /**
21863          * @scope Roo.dd.DropTarget
21864          */
21865          
21866          /**
21867          * @event enter
21868          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21869          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21870          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21871          * 
21872          * IMPORTANT : it should set this.overClass and this.dropAllowed
21873          * 
21874          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21875          * @param {Event} e The event
21876          * @param {Object} data An object containing arbitrary data supplied by the drag source
21877          */
21878         "enter" : true,
21879         
21880          /**
21881          * @event over
21882          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21883          * This method will be called on every mouse movement while the drag source is over the drop target.
21884          * This default implementation simply returns the dropAllowed config value.
21885          * 
21886          * IMPORTANT : it should set this.dropAllowed
21887          * 
21888          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21889          * @param {Event} e The event
21890          * @param {Object} data An object containing arbitrary data supplied by the drag source
21891          
21892          */
21893         "over" : true,
21894         /**
21895          * @event out
21896          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21897          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21898          * overClass (if any) from the drop element.
21899          * 
21900          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901          * @param {Event} e The event
21902          * @param {Object} data An object containing arbitrary data supplied by the drag source
21903          */
21904          "out" : true,
21905          
21906         /**
21907          * @event drop
21908          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21909          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21910          * implementation that does something to process the drop event and returns true so that the drag source's
21911          * repair action does not run.
21912          * 
21913          * IMPORTANT : it should set this.success
21914          * 
21915          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21916          * @param {Event} e The event
21917          * @param {Object} data An object containing arbitrary data supplied by the drag source
21918         */
21919          "drop" : true
21920     });
21921             
21922      
21923     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21924         this.el.dom, 
21925         this.ddGroup || this.group,
21926         {
21927             isTarget: true,
21928             listeners : listeners || {} 
21929            
21930         
21931         }
21932     );
21933
21934 };
21935
21936 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21937     /**
21938      * @cfg {String} overClass
21939      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21940      */
21941      /**
21942      * @cfg {String} ddGroup
21943      * The drag drop group to handle drop events for
21944      */
21945      
21946     /**
21947      * @cfg {String} dropAllowed
21948      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21949      */
21950     dropAllowed : "x-dd-drop-ok",
21951     /**
21952      * @cfg {String} dropNotAllowed
21953      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21954      */
21955     dropNotAllowed : "x-dd-drop-nodrop",
21956     /**
21957      * @cfg {boolean} success
21958      * set this after drop listener.. 
21959      */
21960     success : false,
21961     /**
21962      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21963      * if the drop point is valid for over/enter..
21964      */
21965     valid : false,
21966     // private
21967     isTarget : true,
21968
21969     // private
21970     isNotifyTarget : true,
21971     
21972     /**
21973      * @hide
21974      */
21975     notifyEnter : function(dd, e, data)
21976     {
21977         this.valid = true;
21978         this.fireEvent('enter', dd, e, data);
21979         if(this.overClass){
21980             this.el.addClass(this.overClass);
21981         }
21982         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21983             this.valid ? this.dropAllowed : this.dropNotAllowed
21984         );
21985     },
21986
21987     /**
21988      * @hide
21989      */
21990     notifyOver : function(dd, e, data)
21991     {
21992         this.valid = true;
21993         this.fireEvent('over', dd, e, data);
21994         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21995             this.valid ? this.dropAllowed : this.dropNotAllowed
21996         );
21997     },
21998
21999     /**
22000      * @hide
22001      */
22002     notifyOut : function(dd, e, data)
22003     {
22004         this.fireEvent('out', dd, e, data);
22005         if(this.overClass){
22006             this.el.removeClass(this.overClass);
22007         }
22008     },
22009
22010     /**
22011      * @hide
22012      */
22013     notifyDrop : function(dd, e, data)
22014     {
22015         this.success = false;
22016         this.fireEvent('drop', dd, e, data);
22017         return this.success;
22018     }
22019 });/*
22020  * Based on:
22021  * Ext JS Library 1.1.1
22022  * Copyright(c) 2006-2007, Ext JS, LLC.
22023  *
22024  * Originally Released Under LGPL - original licence link has changed is not relivant.
22025  *
22026  * Fork - LGPL
22027  * <script type="text/javascript">
22028  */
22029
22030
22031 /**
22032  * @class Roo.dd.DragZone
22033  * @extends Roo.dd.DragSource
22034  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22035  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22036  * @constructor
22037  * @param {String/HTMLElement/Element} el The container element
22038  * @param {Object} config
22039  */
22040 Roo.dd.DragZone = function(el, config){
22041     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22042     if(this.containerScroll){
22043         Roo.dd.ScrollManager.register(this.el);
22044     }
22045 };
22046
22047 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22048     /**
22049      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22050      * for auto scrolling during drag operations.
22051      */
22052     /**
22053      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22054      * method after a failed drop (defaults to "c3daf9" - light blue)
22055      */
22056
22057     /**
22058      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22059      * for a valid target to drag based on the mouse down. Override this method
22060      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22061      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22062      * @param {EventObject} e The mouse down event
22063      * @return {Object} The dragData
22064      */
22065     getDragData : function(e){
22066         return Roo.dd.Registry.getHandleFromEvent(e);
22067     },
22068     
22069     /**
22070      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22071      * this.dragData.ddel
22072      * @param {Number} x The x position of the click on the dragged object
22073      * @param {Number} y The y position of the click on the dragged object
22074      * @return {Boolean} true to continue the drag, false to cancel
22075      */
22076     onInitDrag : function(x, y){
22077         this.proxy.update(this.dragData.ddel.cloneNode(true));
22078         this.onStartDrag(x, y);
22079         return true;
22080     },
22081     
22082     /**
22083      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22084      */
22085     afterRepair : function(){
22086         if(Roo.enableFx){
22087             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22088         }
22089         this.dragging = false;
22090     },
22091
22092     /**
22093      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22094      * the XY of this.dragData.ddel
22095      * @param {EventObject} e The mouse up event
22096      * @return {Array} The xy location (e.g. [100, 200])
22097      */
22098     getRepairXY : function(e){
22099         return Roo.Element.fly(this.dragData.ddel).getXY();  
22100     }
22101 });/*
22102  * Based on:
22103  * Ext JS Library 1.1.1
22104  * Copyright(c) 2006-2007, Ext JS, LLC.
22105  *
22106  * Originally Released Under LGPL - original licence link has changed is not relivant.
22107  *
22108  * Fork - LGPL
22109  * <script type="text/javascript">
22110  */
22111 /**
22112  * @class Roo.dd.DropZone
22113  * @extends Roo.dd.DropTarget
22114  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22115  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22116  * @constructor
22117  * @param {String/HTMLElement/Element} el The container element
22118  * @param {Object} config
22119  */
22120 Roo.dd.DropZone = function(el, config){
22121     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22122 };
22123
22124 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22125     /**
22126      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22127      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22128      * provide your own custom lookup.
22129      * @param {Event} e The event
22130      * @return {Object} data The custom data
22131      */
22132     getTargetFromEvent : function(e){
22133         return Roo.dd.Registry.getTargetFromEvent(e);
22134     },
22135
22136     /**
22137      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22138      * that it has registered.  This method has no default implementation and should be overridden to provide
22139      * node-specific processing if necessary.
22140      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22141      * {@link #getTargetFromEvent} for this node)
22142      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22143      * @param {Event} e The event
22144      * @param {Object} data An object containing arbitrary data supplied by the drag source
22145      */
22146     onNodeEnter : function(n, dd, e, data){
22147         
22148     },
22149
22150     /**
22151      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22152      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22153      * overridden to provide the proper feedback.
22154      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22155      * {@link #getTargetFromEvent} for this node)
22156      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22157      * @param {Event} e The event
22158      * @param {Object} data An object containing arbitrary data supplied by the drag source
22159      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22160      * underlying {@link Roo.dd.StatusProxy} can be updated
22161      */
22162     onNodeOver : function(n, dd, e, data){
22163         return this.dropAllowed;
22164     },
22165
22166     /**
22167      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22168      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22169      * node-specific processing if necessary.
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      */
22176     onNodeOut : function(n, dd, e, data){
22177         
22178     },
22179
22180     /**
22181      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22182      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22183      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22184      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22185      * {@link #getTargetFromEvent} for this node)
22186      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22187      * @param {Event} e The event
22188      * @param {Object} data An object containing arbitrary data supplied by the drag source
22189      * @return {Boolean} True if the drop was valid, else false
22190      */
22191     onNodeDrop : function(n, dd, e, data){
22192         return false;
22193     },
22194
22195     /**
22196      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22197      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22198      * it should be overridden to provide the proper feedback if necessary.
22199      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200      * @param {Event} e The event
22201      * @param {Object} data An object containing arbitrary data supplied by the drag source
22202      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22203      * underlying {@link Roo.dd.StatusProxy} can be updated
22204      */
22205     onContainerOver : function(dd, e, data){
22206         return this.dropNotAllowed;
22207     },
22208
22209     /**
22210      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22211      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22212      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22213      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22214      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22215      * @param {Event} e The event
22216      * @param {Object} data An object containing arbitrary data supplied by the drag source
22217      * @return {Boolean} True if the drop was valid, else false
22218      */
22219     onContainerDrop : function(dd, e, data){
22220         return false;
22221     },
22222
22223     /**
22224      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22225      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22226      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22227      * you should override this method and provide a custom implementation.
22228      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22229      * @param {Event} e The event
22230      * @param {Object} data An object containing arbitrary data supplied by the drag source
22231      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22232      * underlying {@link Roo.dd.StatusProxy} can be updated
22233      */
22234     notifyEnter : function(dd, e, data){
22235         return this.dropNotAllowed;
22236     },
22237
22238     /**
22239      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22240      * This method will be called on every mouse movement while the drag source is over the drop zone.
22241      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22242      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22243      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22244      * registered node, it will call {@link #onContainerOver}.
22245      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22246      * @param {Event} e The event
22247      * @param {Object} data An object containing arbitrary data supplied by the drag source
22248      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22249      * underlying {@link Roo.dd.StatusProxy} can be updated
22250      */
22251     notifyOver : function(dd, e, data){
22252         var n = this.getTargetFromEvent(e);
22253         if(!n){ // not over valid drop target
22254             if(this.lastOverNode){
22255                 this.onNodeOut(this.lastOverNode, dd, e, data);
22256                 this.lastOverNode = null;
22257             }
22258             return this.onContainerOver(dd, e, data);
22259         }
22260         if(this.lastOverNode != n){
22261             if(this.lastOverNode){
22262                 this.onNodeOut(this.lastOverNode, dd, e, data);
22263             }
22264             this.onNodeEnter(n, dd, e, data);
22265             this.lastOverNode = n;
22266         }
22267         return this.onNodeOver(n, dd, e, data);
22268     },
22269
22270     /**
22271      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22272      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22273      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22274      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22275      * @param {Event} e The event
22276      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22277      */
22278     notifyOut : function(dd, e, data){
22279         if(this.lastOverNode){
22280             this.onNodeOut(this.lastOverNode, dd, e, data);
22281             this.lastOverNode = null;
22282         }
22283     },
22284
22285     /**
22286      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22287      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22288      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22289      * otherwise it will call {@link #onContainerDrop}.
22290      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22291      * @param {Event} e The event
22292      * @param {Object} data An object containing arbitrary data supplied by the drag source
22293      * @return {Boolean} True if the drop was valid, else false
22294      */
22295     notifyDrop : function(dd, e, data){
22296         if(this.lastOverNode){
22297             this.onNodeOut(this.lastOverNode, dd, e, data);
22298             this.lastOverNode = null;
22299         }
22300         var n = this.getTargetFromEvent(e);
22301         return n ?
22302             this.onNodeDrop(n, dd, e, data) :
22303             this.onContainerDrop(dd, e, data);
22304     },
22305
22306     // private
22307     triggerCacheRefresh : function(){
22308         Roo.dd.DDM.refreshCache(this.groups);
22309     }  
22310 });