roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             console.log(s);
346             
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         }
672         
673     });
674
675
676 })();
677
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
680                 "Roo.app", "Roo.ux",
681                 "Roo.bootstrap",
682                 "Roo.bootstrap.dash");
683 /*
684  * Based on:
685  * Ext JS Library 1.1.1
686  * Copyright(c) 2006-2007, Ext JS, LLC.
687  *
688  * Originally Released Under LGPL - original licence link has changed is not relivant.
689  *
690  * Fork - LGPL
691  * <script type="text/javascript">
692  */
693
694 (function() {    
695     // wrappedn so fnCleanup is not in global scope...
696     if(Roo.isIE) {
697         function fnCleanUp() {
698             var p = Function.prototype;
699             delete p.createSequence;
700             delete p.defer;
701             delete p.createDelegate;
702             delete p.createCallback;
703             delete p.createInterceptor;
704
705             window.detachEvent("onunload", fnCleanUp);
706         }
707         window.attachEvent("onunload", fnCleanUp);
708     }
709 })();
710
711
712 /**
713  * @class Function
714  * These functions are available on every Function object (any JavaScript function).
715  */
716 Roo.apply(Function.prototype, {
717      /**
718      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720      * Will create a function that is bound to those 2 args.
721      * @return {Function} The new function
722     */
723     createCallback : function(/*args...*/){
724         // make args available, in function below
725         var args = arguments;
726         var method = this;
727         return function() {
728             return method.apply(window, args);
729         };
730     },
731
732     /**
733      * Creates a delegate (callback) that sets the scope to obj.
734      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735      * Will create a function that is automatically scoped to this.
736      * @param {Object} obj (optional) The object for which the scope is set
737      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739      *                                             if a number the args are inserted at the specified position
740      * @return {Function} The new function
741      */
742     createDelegate : function(obj, args, appendArgs){
743         var method = this;
744         return function() {
745             var callArgs = args || arguments;
746             if(appendArgs === true){
747                 callArgs = Array.prototype.slice.call(arguments, 0);
748                 callArgs = callArgs.concat(args);
749             }else if(typeof appendArgs == "number"){
750                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
753             }
754             return method.apply(obj || window, callArgs);
755         };
756     },
757
758     /**
759      * Calls this function after the number of millseconds specified.
760      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761      * @param {Object} obj (optional) The object for which the scope is set
762      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764      *                                             if a number the args are inserted at the specified position
765      * @return {Number} The timeout id that can be used with clearTimeout
766      */
767     defer : function(millis, obj, args, appendArgs){
768         var fn = this.createDelegate(obj, args, appendArgs);
769         if(millis){
770             return setTimeout(fn, millis);
771         }
772         fn();
773         return 0;
774     },
775     /**
776      * Create a combined function call sequence of the original function + the passed function.
777      * The resulting function returns the results of the original function.
778      * The passed fcn is called with the parameters of the original function
779      * @param {Function} fcn The function to sequence
780      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781      * @return {Function} The new function
782      */
783     createSequence : function(fcn, scope){
784         if(typeof fcn != "function"){
785             return this;
786         }
787         var method = this;
788         return function() {
789             var retval = method.apply(this || window, arguments);
790             fcn.apply(scope || this || window, arguments);
791             return retval;
792         };
793     },
794
795     /**
796      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797      * The resulting function returns the results of the original function.
798      * The passed fcn is called with the parameters of the original function.
799      * @addon
800      * @param {Function} fcn The function to call before the original
801      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802      * @return {Function} The new function
803      */
804     createInterceptor : function(fcn, scope){
805         if(typeof fcn != "function"){
806             return this;
807         }
808         var method = this;
809         return function() {
810             fcn.target = this;
811             fcn.method = method;
812             if(fcn.apply(scope || this || window, arguments) === false){
813                 return;
814             }
815             return method.apply(this || window, arguments);
816         };
817     }
818 });
819 /*
820  * Based on:
821  * Ext JS Library 1.1.1
822  * Copyright(c) 2006-2007, Ext JS, LLC.
823  *
824  * Originally Released Under LGPL - original licence link has changed is not relivant.
825  *
826  * Fork - LGPL
827  * <script type="text/javascript">
828  */
829
830 Roo.applyIf(String, {
831     
832     /** @scope String */
833     
834     /**
835      * Escapes the passed string for ' and \
836      * @param {String} string The string to escape
837      * @return {String} The escaped string
838      * @static
839      */
840     escape : function(string) {
841         return string.replace(/('|\\)/g, "\\$1");
842     },
843
844     /**
845      * Pads the left side of a string with a specified character.  This is especially useful
846      * for normalizing number and date strings.  Example usage:
847      * <pre><code>
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
850 </code></pre>
851      * @param {String} string The original string
852      * @param {Number} size The total length of the output string
853      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854      * @return {String} The padded string
855      * @static
856      */
857     leftPad : function (val, size, ch) {
858         var result = new String(val);
859         if(ch === null || ch === undefined || ch === '') {
860             ch = " ";
861         }
862         while (result.length < size) {
863             result = ch + result;
864         }
865         return result;
866     },
867
868     /**
869      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
870      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
871      * <pre><code>
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
875 </code></pre>
876      * @param {String} string The tokenized string to be formatted
877      * @param {String} value1 The value to replace token {0}
878      * @param {String} value2 Etc...
879      * @return {String} The formatted string
880      * @static
881      */
882     format : function(format){
883         var args = Array.prototype.slice.call(arguments, 1);
884         return format.replace(/\{(\d+)\}/g, function(m, i){
885             return Roo.util.Format.htmlEncode(args[i]);
886         });
887     }
888 });
889
890 /**
891  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
892  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
893  * they are already different, the first value passed in is returned.  Note that this method returns the new value
894  * but does not change the current string.
895  * <pre><code>
896 // alternate sort directions
897 sort = sort.toggle('ASC', 'DESC');
898
899 // instead of conditional logic:
900 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
901 </code></pre>
902  * @param {String} value The value to compare to the current string
903  * @param {String} other The new value to use if the string already equals the first value passed in
904  * @return {String} The new value
905  */
906  
907 String.prototype.toggle = function(value, other){
908     return this == value ? other : value;
909 };/*
910  * Based on:
911  * Ext JS Library 1.1.1
912  * Copyright(c) 2006-2007, Ext JS, LLC.
913  *
914  * Originally Released Under LGPL - original licence link has changed is not relivant.
915  *
916  * Fork - LGPL
917  * <script type="text/javascript">
918  */
919
920  /**
921  * @class Number
922  */
923 Roo.applyIf(Number.prototype, {
924     /**
925      * Checks whether or not the current number is within a desired range.  If the number is already within the
926      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
927      * exceeded.  Note that this method returns the constrained value but does not change the current number.
928      * @param {Number} min The minimum number in the range
929      * @param {Number} max The maximum number in the range
930      * @return {Number} The constrained value if outside the range, otherwise the current value
931      */
932     constrain : function(min, max){
933         return Math.min(Math.max(this, min), max);
934     }
935 });/*
936  * Based on:
937  * Ext JS Library 1.1.1
938  * Copyright(c) 2006-2007, Ext JS, LLC.
939  *
940  * Originally Released Under LGPL - original licence link has changed is not relivant.
941  *
942  * Fork - LGPL
943  * <script type="text/javascript">
944  */
945  /**
946  * @class Array
947  */
948 Roo.applyIf(Array.prototype, {
949     /**
950      * 
951      * Checks whether or not the specified object exists in the array.
952      * @param {Object} o The object to check for
953      * @return {Number} The index of o in the array (or -1 if it is not found)
954      */
955     indexOf : function(o){
956        for (var i = 0, len = this.length; i < len; i++){
957               if(this[i] == o) { return i; }
958        }
959            return -1;
960     },
961
962     /**
963      * Removes the specified object from the array.  If the object is not found nothing happens.
964      * @param {Object} o The object to remove
965      */
966     remove : function(o){
967        var index = this.indexOf(o);
968        if(index != -1){
969            this.splice(index, 1);
970        }
971     },
972     /**
973      * Map (JS 1.6 compatibility)
974      * @param {Function} function  to call
975      */
976     map : function(fun )
977     {
978         var len = this.length >>> 0;
979         if (typeof fun != "function") {
980             throw new TypeError();
981         }
982         var res = new Array(len);
983         var thisp = arguments[1];
984         for (var i = 0; i < len; i++)
985         {
986             if (i in this) {
987                 res[i] = fun.call(thisp, this[i], i, this);
988             }
989         }
990
991         return res;
992     }
993     
994 });
995
996
997  
998 /*
999  * Based on:
1000  * Ext JS Library 1.1.1
1001  * Copyright(c) 2006-2007, Ext JS, LLC.
1002  *
1003  * Originally Released Under LGPL - original licence link has changed is not relivant.
1004  *
1005  * Fork - LGPL
1006  * <script type="text/javascript">
1007  */
1008
1009 /**
1010  * @class Date
1011  *
1012  * The date parsing and format syntax is a subset of
1013  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1014  * supported will provide results equivalent to their PHP versions.
1015  *
1016  * Following is the list of all currently supported formats:
1017  *<pre>
1018 Sample date:
1019 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1020
1021 Format  Output      Description
1022 ------  ----------  --------------------------------------------------------------
1023   d      10         Day of the month, 2 digits with leading zeros
1024   D      Wed        A textual representation of a day, three letters
1025   j      10         Day of the month without leading zeros
1026   l      Wednesday  A full textual representation of the day of the week
1027   S      th         English ordinal day of month suffix, 2 chars (use with j)
1028   w      3          Numeric representation of the day of the week
1029   z      9          The julian date, or day of the year (0-365)
1030   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1031   F      January    A full textual representation of the month
1032   m      01         Numeric representation of a month, with leading zeros
1033   M      Jan        Month name abbreviation, three letters
1034   n      1          Numeric representation of a month, without leading zeros
1035   t      31         Number of days in the given month
1036   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1037   Y      2007       A full numeric representation of a year, 4 digits
1038   y      07         A two digit representation of a year
1039   a      pm         Lowercase Ante meridiem and Post meridiem
1040   A      PM         Uppercase Ante meridiem and Post meridiem
1041   g      3          12-hour format of an hour without leading zeros
1042   G      15         24-hour format of an hour without leading zeros
1043   h      03         12-hour format of an hour with leading zeros
1044   H      15         24-hour format of an hour with leading zeros
1045   i      05         Minutes with leading zeros
1046   s      01         Seconds, with leading zeros
1047   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1048   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1049   T      CST        Timezone setting of the machine running the code
1050   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1051 </pre>
1052  *
1053  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1054  * <pre><code>
1055 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1056 document.write(dt.format('Y-m-d'));                         //2007-01-10
1057 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1058 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1059  </code></pre>
1060  *
1061  * Here are some standard date/time patterns that you might find helpful.  They
1062  * are not part of the source of Date.js, but to use them you can simply copy this
1063  * block of code into any script that is included after Date.js and they will also become
1064  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1065  * <pre><code>
1066 Date.patterns = {
1067     ISO8601Long:"Y-m-d H:i:s",
1068     ISO8601Short:"Y-m-d",
1069     ShortDate: "n/j/Y",
1070     LongDate: "l, F d, Y",
1071     FullDateTime: "l, F d, Y g:i:s A",
1072     MonthDay: "F d",
1073     ShortTime: "g:i A",
1074     LongTime: "g:i:s A",
1075     SortableDateTime: "Y-m-d\\TH:i:s",
1076     UniversalSortableDateTime: "Y-m-d H:i:sO",
1077     YearMonth: "F, Y"
1078 };
1079 </code></pre>
1080  *
1081  * Example usage:
1082  * <pre><code>
1083 var dt = new Date();
1084 document.write(dt.format(Date.patterns.ShortDate));
1085  </code></pre>
1086  */
1087
1088 /*
1089  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1090  * They generate precompiled functions from date formats instead of parsing and
1091  * processing the pattern every time you format a date.  These functions are available
1092  * on every Date object (any javascript function).
1093  *
1094  * The original article and download are here:
1095  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096  *
1097  */
1098  
1099  
1100  // was in core
1101 /**
1102  Returns the number of milliseconds between this date and date
1103  @param {Date} date (optional) Defaults to now
1104  @return {Number} The diff in milliseconds
1105  @member Date getElapsed
1106  */
1107 Date.prototype.getElapsed = function(date) {
1108         return Math.abs((date || new Date()).getTime()-this.getTime());
1109 };
1110 // was in date file..
1111
1112
1113 // private
1114 Date.parseFunctions = {count:0};
1115 // private
1116 Date.parseRegexes = [];
1117 // private
1118 Date.formatFunctions = {count:0};
1119
1120 // private
1121 Date.prototype.dateFormat = function(format) {
1122     if (Date.formatFunctions[format] == null) {
1123         Date.createNewFormat(format);
1124     }
1125     var func = Date.formatFunctions[format];
1126     return this[func]();
1127 };
1128
1129
1130 /**
1131  * Formats a date given the supplied format string
1132  * @param {String} format The format string
1133  * @return {String} The formatted date
1134  * @method
1135  */
1136 Date.prototype.format = Date.prototype.dateFormat;
1137
1138 // private
1139 Date.createNewFormat = function(format) {
1140     var funcName = "format" + Date.formatFunctions.count++;
1141     Date.formatFunctions[format] = funcName;
1142     var code = "Date.prototype." + funcName + " = function(){return ";
1143     var special = false;
1144     var ch = '';
1145     for (var i = 0; i < format.length; ++i) {
1146         ch = format.charAt(i);
1147         if (!special && ch == "\\") {
1148             special = true;
1149         }
1150         else if (special) {
1151             special = false;
1152             code += "'" + String.escape(ch) + "' + ";
1153         }
1154         else {
1155             code += Date.getFormatCode(ch);
1156         }
1157     }
1158     /** eval:var:zzzzzzzzzzzzz */
1159     eval(code.substring(0, code.length - 3) + ";}");
1160 };
1161
1162 // private
1163 Date.getFormatCode = function(character) {
1164     switch (character) {
1165     case "d":
1166         return "String.leftPad(this.getDate(), 2, '0') + ";
1167     case "D":
1168         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1169     case "j":
1170         return "this.getDate() + ";
1171     case "l":
1172         return "Date.dayNames[this.getDay()] + ";
1173     case "S":
1174         return "this.getSuffix() + ";
1175     case "w":
1176         return "this.getDay() + ";
1177     case "z":
1178         return "this.getDayOfYear() + ";
1179     case "W":
1180         return "this.getWeekOfYear() + ";
1181     case "F":
1182         return "Date.monthNames[this.getMonth()] + ";
1183     case "m":
1184         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1185     case "M":
1186         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1187     case "n":
1188         return "(this.getMonth() + 1) + ";
1189     case "t":
1190         return "this.getDaysInMonth() + ";
1191     case "L":
1192         return "(this.isLeapYear() ? 1 : 0) + ";
1193     case "Y":
1194         return "this.getFullYear() + ";
1195     case "y":
1196         return "('' + this.getFullYear()).substring(2, 4) + ";
1197     case "a":
1198         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1199     case "A":
1200         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1201     case "g":
1202         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1203     case "G":
1204         return "this.getHours() + ";
1205     case "h":
1206         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1207     case "H":
1208         return "String.leftPad(this.getHours(), 2, '0') + ";
1209     case "i":
1210         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1211     case "s":
1212         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1213     case "O":
1214         return "this.getGMTOffset() + ";
1215     case "P":
1216         return "this.getGMTColonOffset() + ";
1217     case "T":
1218         return "this.getTimezone() + ";
1219     case "Z":
1220         return "(this.getTimezoneOffset() * -60) + ";
1221     default:
1222         return "'" + String.escape(character) + "' + ";
1223     }
1224 };
1225
1226 /**
1227  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1228  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1229  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1230  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1231  * string or the parse operation will fail.
1232  * Example Usage:
1233 <pre><code>
1234 //dt = Fri May 25 2007 (current date)
1235 var dt = new Date();
1236
1237 //dt = Thu May 25 2006 (today's month/day in 2006)
1238 dt = Date.parseDate("2006", "Y");
1239
1240 //dt = Sun Jan 15 2006 (all date parts specified)
1241 dt = Date.parseDate("2006-1-15", "Y-m-d");
1242
1243 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1244 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1245 </code></pre>
1246  * @param {String} input The unparsed date as a string
1247  * @param {String} format The format the date is in
1248  * @return {Date} The parsed date
1249  * @static
1250  */
1251 Date.parseDate = function(input, format) {
1252     if (Date.parseFunctions[format] == null) {
1253         Date.createParser(format);
1254     }
1255     var func = Date.parseFunctions[format];
1256     return Date[func](input);
1257 };
1258 /**
1259  * @private
1260  */
1261
1262 Date.createParser = function(format) {
1263     var funcName = "parse" + Date.parseFunctions.count++;
1264     var regexNum = Date.parseRegexes.length;
1265     var currentGroup = 1;
1266     Date.parseFunctions[format] = funcName;
1267
1268     var code = "Date." + funcName + " = function(input){\n"
1269         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1270         + "var d = new Date();\n"
1271         + "y = d.getFullYear();\n"
1272         + "m = d.getMonth();\n"
1273         + "d = d.getDate();\n"
1274         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1275         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1276         + "if (results && results.length > 0) {";
1277     var regex = "";
1278
1279     var special = false;
1280     var ch = '';
1281     for (var i = 0; i < format.length; ++i) {
1282         ch = format.charAt(i);
1283         if (!special && ch == "\\") {
1284             special = true;
1285         }
1286         else if (special) {
1287             special = false;
1288             regex += String.escape(ch);
1289         }
1290         else {
1291             var obj = Date.formatCodeToRegex(ch, currentGroup);
1292             currentGroup += obj.g;
1293             regex += obj.s;
1294             if (obj.g && obj.c) {
1295                 code += obj.c;
1296             }
1297         }
1298     }
1299
1300     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1301         + "{v = new Date(y, m, d, h, i, s);}\n"
1302         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1303         + "{v = new Date(y, m, d, h, i);}\n"
1304         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1305         + "{v = new Date(y, m, d, h);}\n"
1306         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1307         + "{v = new Date(y, m, d);}\n"
1308         + "else if (y >= 0 && m >= 0)\n"
1309         + "{v = new Date(y, m);}\n"
1310         + "else if (y >= 0)\n"
1311         + "{v = new Date(y);}\n"
1312         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1313         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1314         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1315         + ";}";
1316
1317     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1318     /** eval:var:zzzzzzzzzzzzz */
1319     eval(code);
1320 };
1321
1322 // private
1323 Date.formatCodeToRegex = function(character, currentGroup) {
1324     switch (character) {
1325     case "D":
1326         return {g:0,
1327         c:null,
1328         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1329     case "j":
1330         return {g:1,
1331             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1332             s:"(\\d{1,2})"}; // day of month without leading zeroes
1333     case "d":
1334         return {g:1,
1335             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1336             s:"(\\d{2})"}; // day of month with leading zeroes
1337     case "l":
1338         return {g:0,
1339             c:null,
1340             s:"(?:" + Date.dayNames.join("|") + ")"};
1341     case "S":
1342         return {g:0,
1343             c:null,
1344             s:"(?:st|nd|rd|th)"};
1345     case "w":
1346         return {g:0,
1347             c:null,
1348             s:"\\d"};
1349     case "z":
1350         return {g:0,
1351             c:null,
1352             s:"(?:\\d{1,3})"};
1353     case "W":
1354         return {g:0,
1355             c:null,
1356             s:"(?:\\d{2})"};
1357     case "F":
1358         return {g:1,
1359             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1360             s:"(" + Date.monthNames.join("|") + ")"};
1361     case "M":
1362         return {g:1,
1363             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1364             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1365     case "n":
1366         return {g:1,
1367             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1368             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1369     case "m":
1370         return {g:1,
1371             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1372             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1373     case "t":
1374         return {g:0,
1375             c:null,
1376             s:"\\d{1,2}"};
1377     case "L":
1378         return {g:0,
1379             c:null,
1380             s:"(?:1|0)"};
1381     case "Y":
1382         return {g:1,
1383             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{4})"};
1385     case "y":
1386         return {g:1,
1387             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1388                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1389             s:"(\\d{1,2})"};
1390     case "a":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'am') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(am|pm)"};
1396     case "A":
1397         return {g:1,
1398             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1399                 + "if (h == 12) { h = 0; }\n"
1400                 + "} else { if (h < 12) { h += 12; }}",
1401             s:"(AM|PM)"};
1402     case "g":
1403     case "G":
1404         return {g:1,
1405             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1406             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1407     case "h":
1408     case "H":
1409         return {g:1,
1410             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1411             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1412     case "i":
1413         return {g:1,
1414             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1415             s:"(\\d{2})"};
1416     case "s":
1417         return {g:1,
1418             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1419             s:"(\\d{2})"};
1420     case "O":
1421         return {g:1,
1422             c:[
1423                 "o = results[", currentGroup, "];\n",
1424                 "var sn = o.substring(0,1);\n", // get + / - sign
1425                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1426                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1427                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1428                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429             ].join(""),
1430             s:"([+\-]\\d{2,4})"};
1431     
1432     
1433     case "P":
1434         return {g:1,
1435                 c:[
1436                    "o = results[", currentGroup, "];\n",
1437                    "var sn = o.substring(0,1);\n",
1438                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1439                    "var mn = o.substring(4,6) % 60;\n",
1440                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1441                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1442             ].join(""),
1443             s:"([+\-]\\d{4})"};
1444     case "T":
1445         return {g:0,
1446             c:null,
1447             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1448     case "Z":
1449         return {g:1,
1450             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1451                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1452             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1453     default:
1454         return {g:0,
1455             c:null,
1456             s:String.escape(character)};
1457     }
1458 };
1459
1460 /**
1461  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1462  * @return {String} The abbreviated timezone name (e.g. 'CST')
1463  */
1464 Date.prototype.getTimezone = function() {
1465     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1466 };
1467
1468 /**
1469  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1470  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1471  */
1472 Date.prototype.getGMTOffset = function() {
1473     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1474         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1475         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1476 };
1477
1478 /**
1479  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1480  * @return {String} 2-characters representing hours and 2-characters representing minutes
1481  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1482  */
1483 Date.prototype.getGMTColonOffset = function() {
1484         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1485                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1486                 + ":"
1487                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1488 }
1489
1490 /**
1491  * Get the numeric day number of the year, adjusted for leap year.
1492  * @return {Number} 0 through 364 (365 in leap years)
1493  */
1494 Date.prototype.getDayOfYear = function() {
1495     var num = 0;
1496     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1497     for (var i = 0; i < this.getMonth(); ++i) {
1498         num += Date.daysInMonth[i];
1499     }
1500     return num + this.getDate() - 1;
1501 };
1502
1503 /**
1504  * Get the string representation of the numeric week number of the year
1505  * (equivalent to the format specifier 'W').
1506  * @return {String} '00' through '52'
1507  */
1508 Date.prototype.getWeekOfYear = function() {
1509     // Skip to Thursday of this week
1510     var now = this.getDayOfYear() + (4 - this.getDay());
1511     // Find the first Thursday of the year
1512     var jan1 = new Date(this.getFullYear(), 0, 1);
1513     var then = (7 - jan1.getDay() + 4);
1514     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1515 };
1516
1517 /**
1518  * Whether or not the current date is in a leap year.
1519  * @return {Boolean} True if the current date is in a leap year, else false
1520  */
1521 Date.prototype.isLeapYear = function() {
1522     var year = this.getFullYear();
1523     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1524 };
1525
1526 /**
1527  * Get the first day of the current month, adjusted for leap year.  The returned value
1528  * is the numeric day index within the week (0-6) which can be used in conjunction with
1529  * the {@link #monthNames} array to retrieve the textual day name.
1530  * Example:
1531  *<pre><code>
1532 var dt = new Date('1/10/2007');
1533 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1534 </code></pre>
1535  * @return {Number} The day number (0-6)
1536  */
1537 Date.prototype.getFirstDayOfMonth = function() {
1538     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1539     return (day < 0) ? (day + 7) : day;
1540 };
1541
1542 /**
1543  * Get the last day of the current month, adjusted for leap year.  The returned value
1544  * is the numeric day index within the week (0-6) which can be used in conjunction with
1545  * the {@link #monthNames} array to retrieve the textual day name.
1546  * Example:
1547  *<pre><code>
1548 var dt = new Date('1/10/2007');
1549 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1550 </code></pre>
1551  * @return {Number} The day number (0-6)
1552  */
1553 Date.prototype.getLastDayOfMonth = function() {
1554     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1555     return (day < 0) ? (day + 7) : day;
1556 };
1557
1558
1559 /**
1560  * Get the first date of this date's month
1561  * @return {Date}
1562  */
1563 Date.prototype.getFirstDateOfMonth = function() {
1564     return new Date(this.getFullYear(), this.getMonth(), 1);
1565 };
1566
1567 /**
1568  * Get the last date of this date's month
1569  * @return {Date}
1570  */
1571 Date.prototype.getLastDateOfMonth = function() {
1572     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1573 };
1574 /**
1575  * Get the number of days in the current month, adjusted for leap year.
1576  * @return {Number} The number of days in the month
1577  */
1578 Date.prototype.getDaysInMonth = function() {
1579     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1580     return Date.daysInMonth[this.getMonth()];
1581 };
1582
1583 /**
1584  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1585  * @return {String} 'st, 'nd', 'rd' or 'th'
1586  */
1587 Date.prototype.getSuffix = function() {
1588     switch (this.getDate()) {
1589         case 1:
1590         case 21:
1591         case 31:
1592             return "st";
1593         case 2:
1594         case 22:
1595             return "nd";
1596         case 3:
1597         case 23:
1598             return "rd";
1599         default:
1600             return "th";
1601     }
1602 };
1603
1604 // private
1605 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1606
1607 /**
1608  * An array of textual month names.
1609  * Override these values for international dates, for example...
1610  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611  * @type Array
1612  * @static
1613  */
1614 Date.monthNames =
1615    ["January",
1616     "February",
1617     "March",
1618     "April",
1619     "May",
1620     "June",
1621     "July",
1622     "August",
1623     "September",
1624     "October",
1625     "November",
1626     "December"];
1627
1628 /**
1629  * An array of textual day names.
1630  * Override these values for international dates, for example...
1631  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632  * @type Array
1633  * @static
1634  */
1635 Date.dayNames =
1636    ["Sunday",
1637     "Monday",
1638     "Tuesday",
1639     "Wednesday",
1640     "Thursday",
1641     "Friday",
1642     "Saturday"];
1643
1644 // private
1645 Date.y2kYear = 50;
1646 // private
1647 Date.monthNumbers = {
1648     Jan:0,
1649     Feb:1,
1650     Mar:2,
1651     Apr:3,
1652     May:4,
1653     Jun:5,
1654     Jul:6,
1655     Aug:7,
1656     Sep:8,
1657     Oct:9,
1658     Nov:10,
1659     Dec:11};
1660
1661 /**
1662  * Creates and returns a new Date instance with the exact same date value as the called instance.
1663  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1664  * variable will also be changed.  When the intention is to create a new variable that will not
1665  * modify the original instance, you should create a clone.
1666  *
1667  * Example of correctly cloning a date:
1668  * <pre><code>
1669 //wrong way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig;
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 05 2006'!
1674
1675 //correct way:
1676 var orig = new Date('10/1/2006');
1677 var copy = orig.clone();
1678 copy.setDate(5);
1679 document.write(orig);  //returns 'Thu Oct 01 2006'
1680 </code></pre>
1681  * @return {Date} The new Date instance
1682  */
1683 Date.prototype.clone = function() {
1684         return new Date(this.getTime());
1685 };
1686
1687 /**
1688  * Clears any time information from this date
1689  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1690  @return {Date} this or the clone
1691  */
1692 Date.prototype.clearTime = function(clone){
1693     if(clone){
1694         return this.clone().clearTime();
1695     }
1696     this.setHours(0);
1697     this.setMinutes(0);
1698     this.setSeconds(0);
1699     this.setMilliseconds(0);
1700     return this;
1701 };
1702
1703 // private
1704 // safari setMonth is broken -- check that this is only donw once...
1705 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1706     Date.brokenSetMonth = Date.prototype.setMonth;
1707         Date.prototype.setMonth = function(num){
1708                 if(num <= -1){
1709                         var n = Math.ceil(-num);
1710                         var back_year = Math.ceil(n/12);
1711                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1712                         this.setFullYear(this.getFullYear() - back_year);
1713                         return Date.brokenSetMonth.call(this, month);
1714                 } else {
1715                         return Date.brokenSetMonth.apply(this, arguments);
1716                 }
1717         };
1718 }
1719
1720 /** Date interval constant 
1721 * @static 
1722 * @type String */
1723 Date.MILLI = "ms";
1724 /** Date interval constant 
1725 * @static 
1726 * @type String */
1727 Date.SECOND = "s";
1728 /** Date interval constant 
1729 * @static 
1730 * @type String */
1731 Date.MINUTE = "mi";
1732 /** Date interval constant 
1733 * @static 
1734 * @type String */
1735 Date.HOUR = "h";
1736 /** Date interval constant 
1737 * @static 
1738 * @type String */
1739 Date.DAY = "d";
1740 /** Date interval constant 
1741 * @static 
1742 * @type String */
1743 Date.MONTH = "mo";
1744 /** Date interval constant 
1745 * @static 
1746 * @type String */
1747 Date.YEAR = "y";
1748
1749 /**
1750  * Provides a convenient method of performing basic date arithmetic.  This method
1751  * does not modify the Date instance being called - it creates and returns
1752  * a new Date instance containing the resulting date value.
1753  *
1754  * Examples:
1755  * <pre><code>
1756 //Basic usage:
1757 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1758 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1759
1760 //Negative values will subtract correctly:
1761 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1762 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1763
1764 //You can even chain several calls together in one line!
1765 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1766 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1767  </code></pre>
1768  *
1769  * @param {String} interval   A valid date interval enum value
1770  * @param {Number} value      The amount to add to the current date
1771  * @return {Date} The new Date instance
1772  */
1773 Date.prototype.add = function(interval, value){
1774   var d = this.clone();
1775   if (!interval || value === 0) { return d; }
1776   switch(interval.toLowerCase()){
1777     case Date.MILLI:
1778       d.setMilliseconds(this.getMilliseconds() + value);
1779       break;
1780     case Date.SECOND:
1781       d.setSeconds(this.getSeconds() + value);
1782       break;
1783     case Date.MINUTE:
1784       d.setMinutes(this.getMinutes() + value);
1785       break;
1786     case Date.HOUR:
1787       d.setHours(this.getHours() + value);
1788       break;
1789     case Date.DAY:
1790       d.setDate(this.getDate() + value);
1791       break;
1792     case Date.MONTH:
1793       var day = this.getDate();
1794       if(day > 28){
1795           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1796       }
1797       d.setDate(day);
1798       d.setMonth(this.getMonth() + value);
1799       break;
1800     case Date.YEAR:
1801       d.setFullYear(this.getFullYear() + value);
1802       break;
1803   }
1804   return d;
1805 };
1806 /*
1807  * Based on:
1808  * Ext JS Library 1.1.1
1809  * Copyright(c) 2006-2007, Ext JS, LLC.
1810  *
1811  * Originally Released Under LGPL - original licence link has changed is not relivant.
1812  *
1813  * Fork - LGPL
1814  * <script type="text/javascript">
1815  */
1816
1817 /**
1818  * @class Roo.lib.Dom
1819  * @static
1820  * 
1821  * Dom utils (from YIU afaik)
1822  * 
1823  **/
1824 Roo.lib.Dom = {
1825     /**
1826      * Get the view width
1827      * @param {Boolean} full True will get the full document, otherwise it's the view width
1828      * @return {Number} The width
1829      */
1830      
1831     getViewWidth : function(full) {
1832         return full ? this.getDocumentWidth() : this.getViewportWidth();
1833     },
1834     /**
1835      * Get the view height
1836      * @param {Boolean} full True will get the full document, otherwise it's the view height
1837      * @return {Number} The height
1838      */
1839     getViewHeight : function(full) {
1840         return full ? this.getDocumentHeight() : this.getViewportHeight();
1841     },
1842
1843     getDocumentHeight: function() {
1844         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1845         return Math.max(scrollHeight, this.getViewportHeight());
1846     },
1847
1848     getDocumentWidth: function() {
1849         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1850         return Math.max(scrollWidth, this.getViewportWidth());
1851     },
1852
1853     getViewportHeight: function() {
1854         var height = self.innerHeight;
1855         var mode = document.compatMode;
1856
1857         if ((mode || Roo.isIE) && !Roo.isOpera) {
1858             height = (mode == "CSS1Compat") ?
1859                      document.documentElement.clientHeight :
1860                      document.body.clientHeight;
1861         }
1862
1863         return height;
1864     },
1865
1866     getViewportWidth: function() {
1867         var width = self.innerWidth;
1868         var mode = document.compatMode;
1869
1870         if (mode || Roo.isIE) {
1871             width = (mode == "CSS1Compat") ?
1872                     document.documentElement.clientWidth :
1873                     document.body.clientWidth;
1874         }
1875         return width;
1876     },
1877
1878     isAncestor : function(p, c) {
1879         p = Roo.getDom(p);
1880         c = Roo.getDom(c);
1881         if (!p || !c) {
1882             return false;
1883         }
1884
1885         if (p.contains && !Roo.isSafari) {
1886             return p.contains(c);
1887         } else if (p.compareDocumentPosition) {
1888             return !!(p.compareDocumentPosition(c) & 16);
1889         } else {
1890             var parent = c.parentNode;
1891             while (parent) {
1892                 if (parent == p) {
1893                     return true;
1894                 }
1895                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1896                     return false;
1897                 }
1898                 parent = parent.parentNode;
1899             }
1900             return false;
1901         }
1902     },
1903
1904     getRegion : function(el) {
1905         return Roo.lib.Region.getRegion(el);
1906     },
1907
1908     getY : function(el) {
1909         return this.getXY(el)[1];
1910     },
1911
1912     getX : function(el) {
1913         return this.getXY(el)[0];
1914     },
1915
1916     getXY : function(el) {
1917         var p, pe, b, scroll, bd = document.body;
1918         el = Roo.getDom(el);
1919         var fly = Roo.lib.AnimBase.fly;
1920         if (el.getBoundingClientRect) {
1921             b = el.getBoundingClientRect();
1922             scroll = fly(document).getScroll();
1923             return [b.left + scroll.left, b.top + scroll.top];
1924         }
1925         var x = 0, y = 0;
1926
1927         p = el;
1928
1929         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930
1931         while (p) {
1932
1933             x += p.offsetLeft;
1934             y += p.offsetTop;
1935
1936             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937                 hasAbsolute = true;
1938             }
1939
1940             if (Roo.isGecko) {
1941                 pe = fly(p);
1942
1943                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1944                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945
1946
1947                 x += bl;
1948                 y += bt;
1949
1950
1951                 if (p != el && pe.getStyle('overflow') != 'visible') {
1952                     x += bl;
1953                     y += bt;
1954                 }
1955             }
1956             p = p.offsetParent;
1957         }
1958
1959         if (Roo.isSafari && hasAbsolute) {
1960             x -= bd.offsetLeft;
1961             y -= bd.offsetTop;
1962         }
1963
1964         if (Roo.isGecko && !hasAbsolute) {
1965             var dbd = fly(bd);
1966             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1967             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1968         }
1969
1970         p = el.parentNode;
1971         while (p && p != bd) {
1972             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1973                 x -= p.scrollLeft;
1974                 y -= p.scrollTop;
1975             }
1976             p = p.parentNode;
1977         }
1978         return [x, y];
1979     },
1980  
1981   
1982
1983
1984     setXY : function(el, xy) {
1985         el = Roo.fly(el, '_setXY');
1986         el.position();
1987         var pts = el.translatePoints(xy);
1988         if (xy[0] !== false) {
1989             el.dom.style.left = pts.left + "px";
1990         }
1991         if (xy[1] !== false) {
1992             el.dom.style.top = pts.top + "px";
1993         }
1994     },
1995
1996     setX : function(el, x) {
1997         this.setXY(el, [x, false]);
1998     },
1999
2000     setY : function(el, y) {
2001         this.setXY(el, [false, y]);
2002     }
2003 };
2004 /*
2005  * Portions of this file are based on pieces of Yahoo User Interface Library
2006  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2007  * YUI licensed under the BSD License:
2008  * http://developer.yahoo.net/yui/license.txt
2009  * <script type="text/javascript">
2010  *
2011  */
2012
2013 Roo.lib.Event = function() {
2014     var loadComplete = false;
2015     var listeners = [];
2016     var unloadListeners = [];
2017     var retryCount = 0;
2018     var onAvailStack = [];
2019     var counter = 0;
2020     var lastError = null;
2021
2022     return {
2023         POLL_RETRYS: 200,
2024         POLL_INTERVAL: 20,
2025         EL: 0,
2026         TYPE: 1,
2027         FN: 2,
2028         WFN: 3,
2029         OBJ: 3,
2030         ADJ_SCOPE: 4,
2031         _interval: null,
2032
2033         startInterval: function() {
2034             if (!this._interval) {
2035                 var self = this;
2036                 var callback = function() {
2037                     self._tryPreloadAttach();
2038                 };
2039                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2040
2041             }
2042         },
2043
2044         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2045             onAvailStack.push({ id:         p_id,
2046                 fn:         p_fn,
2047                 obj:        p_obj,
2048                 override:   p_override,
2049                 checkReady: false    });
2050
2051             retryCount = this.POLL_RETRYS;
2052             this.startInterval();
2053         },
2054
2055
2056         addListener: function(el, eventName, fn) {
2057             el = Roo.getDom(el);
2058             if (!el || !fn) {
2059                 return false;
2060             }
2061
2062             if ("unload" == eventName) {
2063                 unloadListeners[unloadListeners.length] =
2064                 [el, eventName, fn];
2065                 return true;
2066             }
2067
2068             var wrappedFn = function(e) {
2069                 return fn(Roo.lib.Event.getEvent(e));
2070             };
2071
2072             var li = [el, eventName, fn, wrappedFn];
2073
2074             var index = listeners.length;
2075             listeners[index] = li;
2076
2077             this.doAdd(el, eventName, wrappedFn, false);
2078             return true;
2079
2080         },
2081
2082
2083         removeListener: function(el, eventName, fn) {
2084             var i, len;
2085
2086             el = Roo.getDom(el);
2087
2088             if(!fn) {
2089                 return this.purgeElement(el, false, eventName);
2090             }
2091
2092
2093             if ("unload" == eventName) {
2094
2095                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2096                     var li = unloadListeners[i];
2097                     if (li &&
2098                         li[0] == el &&
2099                         li[1] == eventName &&
2100                         li[2] == fn) {
2101                         unloadListeners.splice(i, 1);
2102                         return true;
2103                     }
2104                 }
2105
2106                 return false;
2107             }
2108
2109             var cacheItem = null;
2110
2111
2112             var index = arguments[3];
2113
2114             if ("undefined" == typeof index) {
2115                 index = this._getCacheIndex(el, eventName, fn);
2116             }
2117
2118             if (index >= 0) {
2119                 cacheItem = listeners[index];
2120             }
2121
2122             if (!el || !cacheItem) {
2123                 return false;
2124             }
2125
2126             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2127
2128             delete listeners[index][this.WFN];
2129             delete listeners[index][this.FN];
2130             listeners.splice(index, 1);
2131
2132             return true;
2133
2134         },
2135
2136
2137         getTarget: function(ev, resolveTextNode) {
2138             ev = ev.browserEvent || ev;
2139             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2140             var t = ev.target || ev.srcElement;
2141             return this.resolveTextNode(t);
2142         },
2143
2144
2145         resolveTextNode: function(node) {
2146             if (Roo.isSafari && node && 3 == node.nodeType) {
2147                 return node.parentNode;
2148             } else {
2149                 return node;
2150             }
2151         },
2152
2153
2154         getPageX: function(ev) {
2155             ev = ev.browserEvent || ev;
2156             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2157             var x = ev.pageX;
2158             if (!x && 0 !== x) {
2159                 x = ev.clientX || 0;
2160
2161                 if (Roo.isIE) {
2162                     x += this.getScroll()[1];
2163                 }
2164             }
2165
2166             return x;
2167         },
2168
2169
2170         getPageY: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2173             var y = ev.pageY;
2174             if (!y && 0 !== y) {
2175                 y = ev.clientY || 0;
2176
2177                 if (Roo.isIE) {
2178                     y += this.getScroll()[0];
2179                 }
2180             }
2181
2182
2183             return y;
2184         },
2185
2186
2187         getXY: function(ev) {
2188             ev = ev.browserEvent || ev;
2189             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2190             return [this.getPageX(ev), this.getPageY(ev)];
2191         },
2192
2193
2194         getRelatedTarget: function(ev) {
2195             ev = ev.browserEvent || ev;
2196             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2197             var t = ev.relatedTarget;
2198             if (!t) {
2199                 if (ev.type == "mouseout") {
2200                     t = ev.toElement;
2201                 } else if (ev.type == "mouseover") {
2202                     t = ev.fromElement;
2203                 }
2204             }
2205
2206             return this.resolveTextNode(t);
2207         },
2208
2209
2210         getTime: function(ev) {
2211             ev = ev.browserEvent || ev;
2212             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2213             if (!ev.time) {
2214                 var t = new Date().getTime();
2215                 try {
2216                     ev.time = t;
2217                 } catch(ex) {
2218                     this.lastError = ex;
2219                     return t;
2220                 }
2221             }
2222
2223             return ev.time;
2224         },
2225
2226
2227         stopEvent: function(ev) {
2228             this.stopPropagation(ev);
2229             this.preventDefault(ev);
2230         },
2231
2232
2233         stopPropagation: function(ev) {
2234             ev = ev.browserEvent || ev;
2235             if (ev.stopPropagation) {
2236                 ev.stopPropagation();
2237             } else {
2238                 ev.cancelBubble = true;
2239             }
2240         },
2241
2242
2243         preventDefault: function(ev) {
2244             ev = ev.browserEvent || ev;
2245             if(ev.preventDefault) {
2246                 ev.preventDefault();
2247             } else {
2248                 ev.returnValue = false;
2249             }
2250         },
2251
2252
2253         getEvent: function(e) {
2254             var ev = e || window.event;
2255             if (!ev) {
2256                 var c = this.getEvent.caller;
2257                 while (c) {
2258                     ev = c.arguments[0];
2259                     if (ev && Event == ev.constructor) {
2260                         break;
2261                     }
2262                     c = c.caller;
2263                 }
2264             }
2265             return ev;
2266         },
2267
2268
2269         getCharCode: function(ev) {
2270             ev = ev.browserEvent || ev;
2271             return ev.charCode || ev.keyCode || 0;
2272         },
2273
2274
2275         _getCacheIndex: function(el, eventName, fn) {
2276             for (var i = 0,len = listeners.length; i < len; ++i) {
2277                 var li = listeners[i];
2278                 if (li &&
2279                     li[this.FN] == fn &&
2280                     li[this.EL] == el &&
2281                     li[this.TYPE] == eventName) {
2282                     return i;
2283                 }
2284             }
2285
2286             return -1;
2287         },
2288
2289
2290         elCache: {},
2291
2292
2293         getEl: function(id) {
2294             return document.getElementById(id);
2295         },
2296
2297
2298         clearCache: function() {
2299         },
2300
2301
2302         _load: function(e) {
2303             loadComplete = true;
2304             var EU = Roo.lib.Event;
2305
2306
2307             if (Roo.isIE) {
2308                 EU.doRemove(window, "load", EU._load);
2309             }
2310         },
2311
2312
2313         _tryPreloadAttach: function() {
2314
2315             if (this.locked) {
2316                 return false;
2317             }
2318
2319             this.locked = true;
2320
2321
2322             var tryAgain = !loadComplete;
2323             if (!tryAgain) {
2324                 tryAgain = (retryCount > 0);
2325             }
2326
2327
2328             var notAvail = [];
2329             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2330                 var item = onAvailStack[i];
2331                 if (item) {
2332                     var el = this.getEl(item.id);
2333
2334                     if (el) {
2335                         if (!item.checkReady ||
2336                             loadComplete ||
2337                             el.nextSibling ||
2338                             (document && document.body)) {
2339
2340                             var scope = el;
2341                             if (item.override) {
2342                                 if (item.override === true) {
2343                                     scope = item.obj;
2344                                 } else {
2345                                     scope = item.override;
2346                                 }
2347                             }
2348                             item.fn.call(scope, item.obj);
2349                             onAvailStack[i] = null;
2350                         }
2351                     } else {
2352                         notAvail.push(item);
2353                     }
2354                 }
2355             }
2356
2357             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2358
2359             if (tryAgain) {
2360
2361                 this.startInterval();
2362             } else {
2363                 clearInterval(this._interval);
2364                 this._interval = null;
2365             }
2366
2367             this.locked = false;
2368
2369             return true;
2370
2371         },
2372
2373
2374         purgeElement: function(el, recurse, eventName) {
2375             var elListeners = this.getListeners(el, eventName);
2376             if (elListeners) {
2377                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2378                     var l = elListeners[i];
2379                     this.removeListener(el, l.type, l.fn);
2380                 }
2381             }
2382
2383             if (recurse && el && el.childNodes) {
2384                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2385                     this.purgeElement(el.childNodes[i], recurse, eventName);
2386                 }
2387             }
2388         },
2389
2390
2391         getListeners: function(el, eventName) {
2392             var results = [], searchLists;
2393             if (!eventName) {
2394                 searchLists = [listeners, unloadListeners];
2395             } else if (eventName == "unload") {
2396                 searchLists = [unloadListeners];
2397             } else {
2398                 searchLists = [listeners];
2399             }
2400
2401             for (var j = 0; j < searchLists.length; ++j) {
2402                 var searchList = searchLists[j];
2403                 if (searchList && searchList.length > 0) {
2404                     for (var i = 0,len = searchList.length; i < len; ++i) {
2405                         var l = searchList[i];
2406                         if (l && l[this.EL] === el &&
2407                             (!eventName || eventName === l[this.TYPE])) {
2408                             results.push({
2409                                 type:   l[this.TYPE],
2410                                 fn:     l[this.FN],
2411                                 obj:    l[this.OBJ],
2412                                 adjust: l[this.ADJ_SCOPE],
2413                                 index:  i
2414                             });
2415                         }
2416                     }
2417                 }
2418             }
2419
2420             return (results.length) ? results : null;
2421         },
2422
2423
2424         _unload: function(e) {
2425
2426             var EU = Roo.lib.Event, i, j, l, len, index;
2427
2428             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2429                 l = unloadListeners[i];
2430                 if (l) {
2431                     var scope = window;
2432                     if (l[EU.ADJ_SCOPE]) {
2433                         if (l[EU.ADJ_SCOPE] === true) {
2434                             scope = l[EU.OBJ];
2435                         } else {
2436                             scope = l[EU.ADJ_SCOPE];
2437                         }
2438                     }
2439                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2440                     unloadListeners[i] = null;
2441                     l = null;
2442                     scope = null;
2443                 }
2444             }
2445
2446             unloadListeners = null;
2447
2448             if (listeners && listeners.length > 0) {
2449                 j = listeners.length;
2450                 while (j) {
2451                     index = j - 1;
2452                     l = listeners[index];
2453                     if (l) {
2454                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2455                                 l[EU.FN], index);
2456                     }
2457                     j = j - 1;
2458                 }
2459                 l = null;
2460
2461                 EU.clearCache();
2462             }
2463
2464             EU.doRemove(window, "unload", EU._unload);
2465
2466         },
2467
2468
2469         getScroll: function() {
2470             var dd = document.documentElement, db = document.body;
2471             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2472                 return [dd.scrollTop, dd.scrollLeft];
2473             } else if (db) {
2474                 return [db.scrollTop, db.scrollLeft];
2475             } else {
2476                 return [0, 0];
2477             }
2478         },
2479
2480
2481         doAdd: function () {
2482             if (window.addEventListener) {
2483                 return function(el, eventName, fn, capture) {
2484                     el.addEventListener(eventName, fn, (capture));
2485                 };
2486             } else if (window.attachEvent) {
2487                 return function(el, eventName, fn, capture) {
2488                     el.attachEvent("on" + eventName, fn);
2489                 };
2490             } else {
2491                 return function() {
2492                 };
2493             }
2494         }(),
2495
2496
2497         doRemove: function() {
2498             if (window.removeEventListener) {
2499                 return function (el, eventName, fn, capture) {
2500                     el.removeEventListener(eventName, fn, (capture));
2501                 };
2502             } else if (window.detachEvent) {
2503                 return function (el, eventName, fn) {
2504                     el.detachEvent("on" + eventName, fn);
2505                 };
2506             } else {
2507                 return function() {
2508                 };
2509             }
2510         }()
2511     };
2512     
2513 }();
2514 (function() {     
2515    
2516     var E = Roo.lib.Event;
2517     E.on = E.addListener;
2518     E.un = E.removeListener;
2519
2520     if (document && document.body) {
2521         E._load();
2522     } else {
2523         E.doAdd(window, "load", E._load);
2524     }
2525     E.doAdd(window, "unload", E._unload);
2526     E._tryPreloadAttach();
2527 })();
2528
2529 /*
2530  * Portions of this file are based on pieces of Yahoo User Interface Library
2531  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2532  * YUI licensed under the BSD License:
2533  * http://developer.yahoo.net/yui/license.txt
2534  * <script type="text/javascript">
2535  *
2536  */
2537
2538 (function() {
2539     /**
2540      * @class Roo.lib.Ajax
2541      *
2542      */
2543     Roo.lib.Ajax = {
2544         /**
2545          * @static 
2546          */
2547         request : function(method, uri, cb, data, options) {
2548             if(options){
2549                 var hs = options.headers;
2550                 if(hs){
2551                     for(var h in hs){
2552                         if(hs.hasOwnProperty(h)){
2553                             this.initHeader(h, hs[h], false);
2554                         }
2555                     }
2556                 }
2557                 if(options.xmlData){
2558                     this.initHeader('Content-Type', 'text/xml', false);
2559                     method = 'POST';
2560                     data = options.xmlData;
2561                 }
2562             }
2563
2564             return this.asyncRequest(method, uri, cb, data);
2565         },
2566
2567         serializeForm : function(form) {
2568             if(typeof form == 'string') {
2569                 form = (document.getElementById(form) || document.forms[form]);
2570             }
2571
2572             var el, name, val, disabled, data = '', hasSubmit = false;
2573             for (var i = 0; i < form.elements.length; i++) {
2574                 el = form.elements[i];
2575                 disabled = form.elements[i].disabled;
2576                 name = form.elements[i].name;
2577                 val = form.elements[i].value;
2578
2579                 if (!disabled && name){
2580                     switch (el.type)
2581                             {
2582                         case 'select-one':
2583                         case 'select-multiple':
2584                             for (var j = 0; j < el.options.length; j++) {
2585                                 if (el.options[j].selected) {
2586                                     if (Roo.isIE) {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                     else {
2590                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2591                                     }
2592                                 }
2593                             }
2594                             break;
2595                         case 'radio':
2596                         case 'checkbox':
2597                             if (el.checked) {
2598                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599                             }
2600                             break;
2601                         case 'file':
2602
2603                         case undefined:
2604
2605                         case 'reset':
2606
2607                         case 'button':
2608
2609                             break;
2610                         case 'submit':
2611                             if(hasSubmit == false) {
2612                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2613                                 hasSubmit = true;
2614                             }
2615                             break;
2616                         default:
2617                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2618                             break;
2619                     }
2620                 }
2621             }
2622             data = data.substr(0, data.length - 1);
2623             return data;
2624         },
2625
2626         headers:{},
2627
2628         hasHeaders:false,
2629
2630         useDefaultHeader:true,
2631
2632         defaultPostHeader:'application/x-www-form-urlencoded',
2633
2634         useDefaultXhrHeader:true,
2635
2636         defaultXhrHeader:'XMLHttpRequest',
2637
2638         hasDefaultHeaders:true,
2639
2640         defaultHeaders:{},
2641
2642         poll:{},
2643
2644         timeout:{},
2645
2646         pollInterval:50,
2647
2648         transactionId:0,
2649
2650         setProgId:function(id)
2651         {
2652             this.activeX.unshift(id);
2653         },
2654
2655         setDefaultPostHeader:function(b)
2656         {
2657             this.useDefaultHeader = b;
2658         },
2659
2660         setDefaultXhrHeader:function(b)
2661         {
2662             this.useDefaultXhrHeader = b;
2663         },
2664
2665         setPollingInterval:function(i)
2666         {
2667             if (typeof i == 'number' && isFinite(i)) {
2668                 this.pollInterval = i;
2669             }
2670         },
2671
2672         createXhrObject:function(transactionId)
2673         {
2674             var obj,http;
2675             try
2676             {
2677
2678                 http = new XMLHttpRequest();
2679
2680                 obj = { conn:http, tId:transactionId };
2681             }
2682             catch(e)
2683             {
2684                 for (var i = 0; i < this.activeX.length; ++i) {
2685                     try
2686                     {
2687
2688                         http = new ActiveXObject(this.activeX[i]);
2689
2690                         obj = { conn:http, tId:transactionId };
2691                         break;
2692                     }
2693                     catch(e) {
2694                     }
2695                 }
2696             }
2697             finally
2698             {
2699                 return obj;
2700             }
2701         },
2702
2703         getConnectionObject:function()
2704         {
2705             var o;
2706             var tId = this.transactionId;
2707
2708             try
2709             {
2710                 o = this.createXhrObject(tId);
2711                 if (o) {
2712                     this.transactionId++;
2713                 }
2714             }
2715             catch(e) {
2716             }
2717             finally
2718             {
2719                 return o;
2720             }
2721         },
2722
2723         asyncRequest:function(method, uri, callback, postData)
2724         {
2725             var o = this.getConnectionObject();
2726
2727             if (!o) {
2728                 return null;
2729             }
2730             else {
2731                 o.conn.open(method, uri, true);
2732
2733                 if (this.useDefaultXhrHeader) {
2734                     if (!this.defaultHeaders['X-Requested-With']) {
2735                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2736                     }
2737                 }
2738
2739                 if(postData && this.useDefaultHeader){
2740                     this.initHeader('Content-Type', this.defaultPostHeader);
2741                 }
2742
2743                  if (this.hasDefaultHeaders || this.hasHeaders) {
2744                     this.setHeader(o);
2745                 }
2746
2747                 this.handleReadyState(o, callback);
2748                 o.conn.send(postData || null);
2749
2750                 return o;
2751             }
2752         },
2753
2754         handleReadyState:function(o, callback)
2755         {
2756             var oConn = this;
2757
2758             if (callback && callback.timeout) {
2759                 
2760                 this.timeout[o.tId] = window.setTimeout(function() {
2761                     oConn.abort(o, callback, true);
2762                 }, callback.timeout);
2763             }
2764
2765             this.poll[o.tId] = window.setInterval(
2766                     function() {
2767                         if (o.conn && o.conn.readyState == 4) {
2768                             window.clearInterval(oConn.poll[o.tId]);
2769                             delete oConn.poll[o.tId];
2770
2771                             if(callback && callback.timeout) {
2772                                 window.clearTimeout(oConn.timeout[o.tId]);
2773                                 delete oConn.timeout[o.tId];
2774                             }
2775
2776                             oConn.handleTransactionResponse(o, callback);
2777                         }
2778                     }
2779                     , this.pollInterval);
2780         },
2781
2782         handleTransactionResponse:function(o, callback, isAbort)
2783         {
2784
2785             if (!callback) {
2786                 this.releaseObject(o);
2787                 return;
2788             }
2789
2790             var httpStatus, responseObject;
2791
2792             try
2793             {
2794                 if (o.conn.status !== undefined && o.conn.status != 0) {
2795                     httpStatus = o.conn.status;
2796                 }
2797                 else {
2798                     httpStatus = 13030;
2799                 }
2800             }
2801             catch(e) {
2802
2803
2804                 httpStatus = 13030;
2805             }
2806
2807             if (httpStatus >= 200 && httpStatus < 300) {
2808                 responseObject = this.createResponseObject(o, callback.argument);
2809                 if (callback.success) {
2810                     if (!callback.scope) {
2811                         callback.success(responseObject);
2812                     }
2813                     else {
2814
2815
2816                         callback.success.apply(callback.scope, [responseObject]);
2817                     }
2818                 }
2819             }
2820             else {
2821                 switch (httpStatus) {
2822
2823                     case 12002:
2824                     case 12029:
2825                     case 12030:
2826                     case 12031:
2827                     case 12152:
2828                     case 13030:
2829                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2830                         if (callback.failure) {
2831                             if (!callback.scope) {
2832                                 callback.failure(responseObject);
2833                             }
2834                             else {
2835                                 callback.failure.apply(callback.scope, [responseObject]);
2836                             }
2837                         }
2838                         break;
2839                     default:
2840                         responseObject = this.createResponseObject(o, callback.argument);
2841                         if (callback.failure) {
2842                             if (!callback.scope) {
2843                                 callback.failure(responseObject);
2844                             }
2845                             else {
2846                                 callback.failure.apply(callback.scope, [responseObject]);
2847                             }
2848                         }
2849                 }
2850             }
2851
2852             this.releaseObject(o);
2853             responseObject = null;
2854         },
2855
2856         createResponseObject:function(o, callbackArg)
2857         {
2858             var obj = {};
2859             var headerObj = {};
2860
2861             try
2862             {
2863                 var headerStr = o.conn.getAllResponseHeaders();
2864                 var header = headerStr.split('\n');
2865                 for (var i = 0; i < header.length; i++) {
2866                     var delimitPos = header[i].indexOf(':');
2867                     if (delimitPos != -1) {
2868                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2869                     }
2870                 }
2871             }
2872             catch(e) {
2873             }
2874
2875             obj.tId = o.tId;
2876             obj.status = o.conn.status;
2877             obj.statusText = o.conn.statusText;
2878             obj.getResponseHeader = headerObj;
2879             obj.getAllResponseHeaders = headerStr;
2880             obj.responseText = o.conn.responseText;
2881             obj.responseXML = o.conn.responseXML;
2882
2883             if (typeof callbackArg !== undefined) {
2884                 obj.argument = callbackArg;
2885             }
2886
2887             return obj;
2888         },
2889
2890         createExceptionObject:function(tId, callbackArg, isAbort)
2891         {
2892             var COMM_CODE = 0;
2893             var COMM_ERROR = 'communication failure';
2894             var ABORT_CODE = -1;
2895             var ABORT_ERROR = 'transaction aborted';
2896
2897             var obj = {};
2898
2899             obj.tId = tId;
2900             if (isAbort) {
2901                 obj.status = ABORT_CODE;
2902                 obj.statusText = ABORT_ERROR;
2903             }
2904             else {
2905                 obj.status = COMM_CODE;
2906                 obj.statusText = COMM_ERROR;
2907             }
2908
2909             if (callbackArg) {
2910                 obj.argument = callbackArg;
2911             }
2912
2913             return obj;
2914         },
2915
2916         initHeader:function(label, value, isDefault)
2917         {
2918             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2919
2920             if (headerObj[label] === undefined) {
2921                 headerObj[label] = value;
2922             }
2923             else {
2924
2925
2926                 headerObj[label] = value + "," + headerObj[label];
2927             }
2928
2929             if (isDefault) {
2930                 this.hasDefaultHeaders = true;
2931             }
2932             else {
2933                 this.hasHeaders = true;
2934             }
2935         },
2936
2937
2938         setHeader:function(o)
2939         {
2940             if (this.hasDefaultHeaders) {
2941                 for (var prop in this.defaultHeaders) {
2942                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2943                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2944                     }
2945                 }
2946             }
2947
2948             if (this.hasHeaders) {
2949                 for (var prop in this.headers) {
2950                     if (this.headers.hasOwnProperty(prop)) {
2951                         o.conn.setRequestHeader(prop, this.headers[prop]);
2952                     }
2953                 }
2954                 this.headers = {};
2955                 this.hasHeaders = false;
2956             }
2957         },
2958
2959         resetDefaultHeaders:function() {
2960             delete this.defaultHeaders;
2961             this.defaultHeaders = {};
2962             this.hasDefaultHeaders = false;
2963         },
2964
2965         abort:function(o, callback, isTimeout)
2966         {
2967             if(this.isCallInProgress(o)) {
2968                 o.conn.abort();
2969                 window.clearInterval(this.poll[o.tId]);
2970                 delete this.poll[o.tId];
2971                 if (isTimeout) {
2972                     delete this.timeout[o.tId];
2973                 }
2974
2975                 this.handleTransactionResponse(o, callback, true);
2976
2977                 return true;
2978             }
2979             else {
2980                 return false;
2981             }
2982         },
2983
2984
2985         isCallInProgress:function(o)
2986         {
2987             if (o && o.conn) {
2988                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2989             }
2990             else {
2991
2992                 return false;
2993             }
2994         },
2995
2996
2997         releaseObject:function(o)
2998         {
2999
3000             o.conn = null;
3001
3002             o = null;
3003         },
3004
3005         activeX:[
3006         'MSXML2.XMLHTTP.3.0',
3007         'MSXML2.XMLHTTP',
3008         'Microsoft.XMLHTTP'
3009         ]
3010
3011
3012     };
3013 })();/*
3014  * Portions of this file are based on pieces of Yahoo User Interface Library
3015  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3016  * YUI licensed under the BSD License:
3017  * http://developer.yahoo.net/yui/license.txt
3018  * <script type="text/javascript">
3019  *
3020  */
3021
3022 Roo.lib.Region = function(t, r, b, l) {
3023     this.top = t;
3024     this[1] = t;
3025     this.right = r;
3026     this.bottom = b;
3027     this.left = l;
3028     this[0] = l;
3029 };
3030
3031
3032 Roo.lib.Region.prototype = {
3033     contains : function(region) {
3034         return ( region.left >= this.left &&
3035                  region.right <= this.right &&
3036                  region.top >= this.top &&
3037                  region.bottom <= this.bottom    );
3038
3039     },
3040
3041     getArea : function() {
3042         return ( (this.bottom - this.top) * (this.right - this.left) );
3043     },
3044
3045     intersect : function(region) {
3046         var t = Math.max(this.top, region.top);
3047         var r = Math.min(this.right, region.right);
3048         var b = Math.min(this.bottom, region.bottom);
3049         var l = Math.max(this.left, region.left);
3050
3051         if (b >= t && r >= l) {
3052             return new Roo.lib.Region(t, r, b, l);
3053         } else {
3054             return null;
3055         }
3056     },
3057     union : function(region) {
3058         var t = Math.min(this.top, region.top);
3059         var r = Math.max(this.right, region.right);
3060         var b = Math.max(this.bottom, region.bottom);
3061         var l = Math.min(this.left, region.left);
3062
3063         return new Roo.lib.Region(t, r, b, l);
3064     },
3065
3066     adjust : function(t, l, b, r) {
3067         this.top += t;
3068         this.left += l;
3069         this.right += r;
3070         this.bottom += b;
3071         return this;
3072     }
3073 };
3074
3075 Roo.lib.Region.getRegion = function(el) {
3076     var p = Roo.lib.Dom.getXY(el);
3077
3078     var t = p[1];
3079     var r = p[0] + el.offsetWidth;
3080     var b = p[1] + el.offsetHeight;
3081     var l = p[0];
3082
3083     return new Roo.lib.Region(t, r, b, l);
3084 };
3085 /*
3086  * Portions of this file are based on pieces of Yahoo User Interface Library
3087  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088  * YUI licensed under the BSD License:
3089  * http://developer.yahoo.net/yui/license.txt
3090  * <script type="text/javascript">
3091  *
3092  */
3093 //@@dep Roo.lib.Region
3094
3095
3096 Roo.lib.Point = function(x, y) {
3097     if (x instanceof Array) {
3098         y = x[1];
3099         x = x[0];
3100     }
3101     this.x = this.right = this.left = this[0] = x;
3102     this.y = this.top = this.bottom = this[1] = y;
3103 };
3104
3105 Roo.lib.Point.prototype = new Roo.lib.Region();
3106 /*
3107  * Portions of this file are based on pieces of Yahoo User Interface Library
3108  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109  * YUI licensed under the BSD License:
3110  * http://developer.yahoo.net/yui/license.txt
3111  * <script type="text/javascript">
3112  *
3113  */
3114  
3115 (function() {   
3116
3117     Roo.lib.Anim = {
3118         scroll : function(el, args, duration, easing, cb, scope) {
3119             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3120         },
3121
3122         motion : function(el, args, duration, easing, cb, scope) {
3123             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3124         },
3125
3126         color : function(el, args, duration, easing, cb, scope) {
3127             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3128         },
3129
3130         run : function(el, args, duration, easing, cb, scope, type) {
3131             type = type || Roo.lib.AnimBase;
3132             if (typeof easing == "string") {
3133                 easing = Roo.lib.Easing[easing];
3134             }
3135             var anim = new type(el, args, duration, easing);
3136             anim.animateX(function() {
3137                 Roo.callback(cb, scope);
3138             });
3139             return anim;
3140         }
3141     };
3142 })();/*
3143  * Portions of this file are based on pieces of Yahoo User Interface Library
3144  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3145  * YUI licensed under the BSD License:
3146  * http://developer.yahoo.net/yui/license.txt
3147  * <script type="text/javascript">
3148  *
3149  */
3150
3151 (function() {    
3152     var libFlyweight;
3153     
3154     function fly(el) {
3155         if (!libFlyweight) {
3156             libFlyweight = new Roo.Element.Flyweight();
3157         }
3158         libFlyweight.dom = el;
3159         return libFlyweight;
3160     }
3161
3162     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3163     
3164    
3165     
3166     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3167         if (el) {
3168             this.init(el, attributes, duration, method);
3169         }
3170     };
3171
3172     Roo.lib.AnimBase.fly = fly;
3173     
3174     
3175     
3176     Roo.lib.AnimBase.prototype = {
3177
3178         toString: function() {
3179             var el = this.getEl();
3180             var id = el.id || el.tagName;
3181             return ("Anim " + id);
3182         },
3183
3184         patterns: {
3185             noNegatives:        /width|height|opacity|padding/i,
3186             offsetAttribute:  /^((width|height)|(top|left))$/,
3187             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3188             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3189         },
3190
3191
3192         doMethod: function(attr, start, end) {
3193             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3194         },
3195
3196
3197         setAttribute: function(attr, val, unit) {
3198             if (this.patterns.noNegatives.test(attr)) {
3199                 val = (val > 0) ? val : 0;
3200             }
3201
3202             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3203         },
3204
3205
3206         getAttribute: function(attr) {
3207             var el = this.getEl();
3208             var val = fly(el).getStyle(attr);
3209
3210             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3211                 return parseFloat(val);
3212             }
3213
3214             var a = this.patterns.offsetAttribute.exec(attr) || [];
3215             var pos = !!( a[3] );
3216             var box = !!( a[2] );
3217
3218
3219             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3220                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3221             } else {
3222                 val = 0;
3223             }
3224
3225             return val;
3226         },
3227
3228
3229         getDefaultUnit: function(attr) {
3230             if (this.patterns.defaultUnit.test(attr)) {
3231                 return 'px';
3232             }
3233
3234             return '';
3235         },
3236
3237         animateX : function(callback, scope) {
3238             var f = function() {
3239                 this.onComplete.removeListener(f);
3240                 if (typeof callback == "function") {
3241                     callback.call(scope || this, this);
3242                 }
3243             };
3244             this.onComplete.addListener(f, this);
3245             this.animate();
3246         },
3247
3248
3249         setRuntimeAttribute: function(attr) {
3250             var start;
3251             var end;
3252             var attributes = this.attributes;
3253
3254             this.runtimeAttributes[attr] = {};
3255
3256             var isset = function(prop) {
3257                 return (typeof prop !== 'undefined');
3258             };
3259
3260             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3261                 return false;
3262             }
3263
3264             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3265
3266
3267             if (isset(attributes[attr]['to'])) {
3268                 end = attributes[attr]['to'];
3269             } else if (isset(attributes[attr]['by'])) {
3270                 if (start.constructor == Array) {
3271                     end = [];
3272                     for (var i = 0, len = start.length; i < len; ++i) {
3273                         end[i] = start[i] + attributes[attr]['by'][i];
3274                     }
3275                 } else {
3276                     end = start + attributes[attr]['by'];
3277                 }
3278             }
3279
3280             this.runtimeAttributes[attr].start = start;
3281             this.runtimeAttributes[attr].end = end;
3282
3283
3284             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3285         },
3286
3287
3288         init: function(el, attributes, duration, method) {
3289
3290             var isAnimated = false;
3291
3292
3293             var startTime = null;
3294
3295
3296             var actualFrames = 0;
3297
3298
3299             el = Roo.getDom(el);
3300
3301
3302             this.attributes = attributes || {};
3303
3304
3305             this.duration = duration || 1;
3306
3307
3308             this.method = method || Roo.lib.Easing.easeNone;
3309
3310
3311             this.useSeconds = true;
3312
3313
3314             this.currentFrame = 0;
3315
3316
3317             this.totalFrames = Roo.lib.AnimMgr.fps;
3318
3319
3320             this.getEl = function() {
3321                 return el;
3322             };
3323
3324
3325             this.isAnimated = function() {
3326                 return isAnimated;
3327             };
3328
3329
3330             this.getStartTime = function() {
3331                 return startTime;
3332             };
3333
3334             this.runtimeAttributes = {};
3335
3336
3337             this.animate = function() {
3338                 if (this.isAnimated()) {
3339                     return false;
3340                 }
3341
3342                 this.currentFrame = 0;
3343
3344                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3345
3346                 Roo.lib.AnimMgr.registerElement(this);
3347             };
3348
3349
3350             this.stop = function(finish) {
3351                 if (finish) {
3352                     this.currentFrame = this.totalFrames;
3353                     this._onTween.fire();
3354                 }
3355                 Roo.lib.AnimMgr.stop(this);
3356             };
3357
3358             var onStart = function() {
3359                 this.onStart.fire();
3360
3361                 this.runtimeAttributes = {};
3362                 for (var attr in this.attributes) {
3363                     this.setRuntimeAttribute(attr);
3364                 }
3365
3366                 isAnimated = true;
3367                 actualFrames = 0;
3368                 startTime = new Date();
3369             };
3370
3371
3372             var onTween = function() {
3373                 var data = {
3374                     duration: new Date() - this.getStartTime(),
3375                     currentFrame: this.currentFrame
3376                 };
3377
3378                 data.toString = function() {
3379                     return (
3380                             'duration: ' + data.duration +
3381                             ', currentFrame: ' + data.currentFrame
3382                             );
3383                 };
3384
3385                 this.onTween.fire(data);
3386
3387                 var runtimeAttributes = this.runtimeAttributes;
3388
3389                 for (var attr in runtimeAttributes) {
3390                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3391                 }
3392
3393                 actualFrames += 1;
3394             };
3395
3396             var onComplete = function() {
3397                 var actual_duration = (new Date() - startTime) / 1000 ;
3398
3399                 var data = {
3400                     duration: actual_duration,
3401                     frames: actualFrames,
3402                     fps: actualFrames / actual_duration
3403                 };
3404
3405                 data.toString = function() {
3406                     return (
3407                             'duration: ' + data.duration +
3408                             ', frames: ' + data.frames +
3409                             ', fps: ' + data.fps
3410                             );
3411                 };
3412
3413                 isAnimated = false;
3414                 actualFrames = 0;
3415                 this.onComplete.fire(data);
3416             };
3417
3418
3419             this._onStart = new Roo.util.Event(this);
3420             this.onStart = new Roo.util.Event(this);
3421             this.onTween = new Roo.util.Event(this);
3422             this._onTween = new Roo.util.Event(this);
3423             this.onComplete = new Roo.util.Event(this);
3424             this._onComplete = new Roo.util.Event(this);
3425             this._onStart.addListener(onStart);
3426             this._onTween.addListener(onTween);
3427             this._onComplete.addListener(onComplete);
3428         }
3429     };
3430 })();
3431 /*
3432  * Portions of this file are based on pieces of Yahoo User Interface Library
3433  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3434  * YUI licensed under the BSD License:
3435  * http://developer.yahoo.net/yui/license.txt
3436  * <script type="text/javascript">
3437  *
3438  */
3439
3440 Roo.lib.AnimMgr = new function() {
3441
3442     var thread = null;
3443
3444
3445     var queue = [];
3446
3447
3448     var tweenCount = 0;
3449
3450
3451     this.fps = 1000;
3452
3453
3454     this.delay = 1;
3455
3456
3457     this.registerElement = function(tween) {
3458         queue[queue.length] = tween;
3459         tweenCount += 1;
3460         tween._onStart.fire();
3461         this.start();
3462     };
3463
3464
3465     this.unRegister = function(tween, index) {
3466         tween._onComplete.fire();
3467         index = index || getIndex(tween);
3468         if (index != -1) {
3469             queue.splice(index, 1);
3470         }
3471
3472         tweenCount -= 1;
3473         if (tweenCount <= 0) {
3474             this.stop();
3475         }
3476     };
3477
3478
3479     this.start = function() {
3480         if (thread === null) {
3481             thread = setInterval(this.run, this.delay);
3482         }
3483     };
3484
3485
3486     this.stop = function(tween) {
3487         if (!tween) {
3488             clearInterval(thread);
3489
3490             for (var i = 0, len = queue.length; i < len; ++i) {
3491                 if (queue[0].isAnimated()) {
3492                     this.unRegister(queue[0], 0);
3493                 }
3494             }
3495
3496             queue = [];
3497             thread = null;
3498             tweenCount = 0;
3499         }
3500         else {
3501             this.unRegister(tween);
3502         }
3503     };
3504
3505
3506     this.run = function() {
3507         for (var i = 0, len = queue.length; i < len; ++i) {
3508             var tween = queue[i];
3509             if (!tween || !tween.isAnimated()) {
3510                 continue;
3511             }
3512
3513             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3514             {
3515                 tween.currentFrame += 1;
3516
3517                 if (tween.useSeconds) {
3518                     correctFrame(tween);
3519                 }
3520                 tween._onTween.fire();
3521             }
3522             else {
3523                 Roo.lib.AnimMgr.stop(tween, i);
3524             }
3525         }
3526     };
3527
3528     var getIndex = function(anim) {
3529         for (var i = 0, len = queue.length; i < len; ++i) {
3530             if (queue[i] == anim) {
3531                 return i;
3532             }
3533         }
3534         return -1;
3535     };
3536
3537
3538     var correctFrame = function(tween) {
3539         var frames = tween.totalFrames;
3540         var frame = tween.currentFrame;
3541         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3542         var elapsed = (new Date() - tween.getStartTime());
3543         var tweak = 0;
3544
3545         if (elapsed < tween.duration * 1000) {
3546             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3547         } else {
3548             tweak = frames - (frame + 1);
3549         }
3550         if (tweak > 0 && isFinite(tweak)) {
3551             if (tween.currentFrame + tweak >= frames) {
3552                 tweak = frames - (frame + 1);
3553             }
3554
3555             tween.currentFrame += tweak;
3556         }
3557     };
3558 };
3559
3560     /*
3561  * Portions of this file are based on pieces of Yahoo User Interface Library
3562  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3563  * YUI licensed under the BSD License:
3564  * http://developer.yahoo.net/yui/license.txt
3565  * <script type="text/javascript">
3566  *
3567  */
3568 Roo.lib.Bezier = new function() {
3569
3570         this.getPosition = function(points, t) {
3571             var n = points.length;
3572             var tmp = [];
3573
3574             for (var i = 0; i < n; ++i) {
3575                 tmp[i] = [points[i][0], points[i][1]];
3576             }
3577
3578             for (var j = 1; j < n; ++j) {
3579                 for (i = 0; i < n - j; ++i) {
3580                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3581                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3582                 }
3583             }
3584
3585             return [ tmp[0][0], tmp[0][1] ];
3586
3587         };
3588     };/*
3589  * Portions of this file are based on pieces of Yahoo User Interface Library
3590  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3591  * YUI licensed under the BSD License:
3592  * http://developer.yahoo.net/yui/license.txt
3593  * <script type="text/javascript">
3594  *
3595  */
3596 (function() {
3597
3598     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3599         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3600     };
3601
3602     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3603
3604     var fly = Roo.lib.AnimBase.fly;
3605     var Y = Roo.lib;
3606     var superclass = Y.ColorAnim.superclass;
3607     var proto = Y.ColorAnim.prototype;
3608
3609     proto.toString = function() {
3610         var el = this.getEl();
3611         var id = el.id || el.tagName;
3612         return ("ColorAnim " + id);
3613     };
3614
3615     proto.patterns.color = /color$/i;
3616     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3617     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3618     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3619     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3620
3621
3622     proto.parseColor = function(s) {
3623         if (s.length == 3) {
3624             return s;
3625         }
3626
3627         var c = this.patterns.hex.exec(s);
3628         if (c && c.length == 4) {
3629             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3630         }
3631
3632         c = this.patterns.rgb.exec(s);
3633         if (c && c.length == 4) {
3634             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3635         }
3636
3637         c = this.patterns.hex3.exec(s);
3638         if (c && c.length == 4) {
3639             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3640         }
3641
3642         return null;
3643     };
3644     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3645     proto.getAttribute = function(attr) {
3646         var el = this.getEl();
3647         if (this.patterns.color.test(attr)) {
3648             var val = fly(el).getStyle(attr);
3649
3650             if (this.patterns.transparent.test(val)) {
3651                 var parent = el.parentNode;
3652                 val = fly(parent).getStyle(attr);
3653
3654                 while (parent && this.patterns.transparent.test(val)) {
3655                     parent = parent.parentNode;
3656                     val = fly(parent).getStyle(attr);
3657                     if (parent.tagName.toUpperCase() == 'HTML') {
3658                         val = '#fff';
3659                     }
3660                 }
3661             }
3662         } else {
3663             val = superclass.getAttribute.call(this, attr);
3664         }
3665
3666         return val;
3667     };
3668     proto.getAttribute = function(attr) {
3669         var el = this.getEl();
3670         if (this.patterns.color.test(attr)) {
3671             var val = fly(el).getStyle(attr);
3672
3673             if (this.patterns.transparent.test(val)) {
3674                 var parent = el.parentNode;
3675                 val = fly(parent).getStyle(attr);
3676
3677                 while (parent && this.patterns.transparent.test(val)) {
3678                     parent = parent.parentNode;
3679                     val = fly(parent).getStyle(attr);
3680                     if (parent.tagName.toUpperCase() == 'HTML') {
3681                         val = '#fff';
3682                     }
3683                 }
3684             }
3685         } else {
3686             val = superclass.getAttribute.call(this, attr);
3687         }
3688
3689         return val;
3690     };
3691
3692     proto.doMethod = function(attr, start, end) {
3693         var val;
3694
3695         if (this.patterns.color.test(attr)) {
3696             val = [];
3697             for (var i = 0, len = start.length; i < len; ++i) {
3698                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3699             }
3700
3701             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3702         }
3703         else {
3704             val = superclass.doMethod.call(this, attr, start, end);
3705         }
3706
3707         return val;
3708     };
3709
3710     proto.setRuntimeAttribute = function(attr) {
3711         superclass.setRuntimeAttribute.call(this, attr);
3712
3713         if (this.patterns.color.test(attr)) {
3714             var attributes = this.attributes;
3715             var start = this.parseColor(this.runtimeAttributes[attr].start);
3716             var end = this.parseColor(this.runtimeAttributes[attr].end);
3717
3718             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3719                 end = this.parseColor(attributes[attr].by);
3720
3721                 for (var i = 0, len = start.length; i < len; ++i) {
3722                     end[i] = start[i] + end[i];
3723                 }
3724             }
3725
3726             this.runtimeAttributes[attr].start = start;
3727             this.runtimeAttributes[attr].end = end;
3728         }
3729     };
3730 })();
3731
3732 /*
3733  * Portions of this file are based on pieces of Yahoo User Interface Library
3734  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3735  * YUI licensed under the BSD License:
3736  * http://developer.yahoo.net/yui/license.txt
3737  * <script type="text/javascript">
3738  *
3739  */
3740 Roo.lib.Easing = {
3741
3742
3743     easeNone: function (t, b, c, d) {
3744         return c * t / d + b;
3745     },
3746
3747
3748     easeIn: function (t, b, c, d) {
3749         return c * (t /= d) * t + b;
3750     },
3751
3752
3753     easeOut: function (t, b, c, d) {
3754         return -c * (t /= d) * (t - 2) + b;
3755     },
3756
3757
3758     easeBoth: function (t, b, c, d) {
3759         if ((t /= d / 2) < 1) {
3760             return c / 2 * t * t + b;
3761         }
3762
3763         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3764     },
3765
3766
3767     easeInStrong: function (t, b, c, d) {
3768         return c * (t /= d) * t * t * t + b;
3769     },
3770
3771
3772     easeOutStrong: function (t, b, c, d) {
3773         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3774     },
3775
3776
3777     easeBothStrong: function (t, b, c, d) {
3778         if ((t /= d / 2) < 1) {
3779             return c / 2 * t * t * t * t + b;
3780         }
3781
3782         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3783     },
3784
3785
3786
3787     elasticIn: function (t, b, c, d, a, p) {
3788         if (t == 0) {
3789             return b;
3790         }
3791         if ((t /= d) == 1) {
3792             return b + c;
3793         }
3794         if (!p) {
3795             p = d * .3;
3796         }
3797
3798         if (!a || a < Math.abs(c)) {
3799             a = c;
3800             var s = p / 4;
3801         }
3802         else {
3803             var s = p / (2 * Math.PI) * Math.asin(c / a);
3804         }
3805
3806         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3807     },
3808
3809
3810     elasticOut: function (t, b, c, d, a, p) {
3811         if (t == 0) {
3812             return b;
3813         }
3814         if ((t /= d) == 1) {
3815             return b + c;
3816         }
3817         if (!p) {
3818             p = d * .3;
3819         }
3820
3821         if (!a || a < Math.abs(c)) {
3822             a = c;
3823             var s = p / 4;
3824         }
3825         else {
3826             var s = p / (2 * Math.PI) * Math.asin(c / a);
3827         }
3828
3829         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3830     },
3831
3832
3833     elasticBoth: function (t, b, c, d, a, p) {
3834         if (t == 0) {
3835             return b;
3836         }
3837
3838         if ((t /= d / 2) == 2) {
3839             return b + c;
3840         }
3841
3842         if (!p) {
3843             p = d * (.3 * 1.5);
3844         }
3845
3846         if (!a || a < Math.abs(c)) {
3847             a = c;
3848             var s = p / 4;
3849         }
3850         else {
3851             var s = p / (2 * Math.PI) * Math.asin(c / a);
3852         }
3853
3854         if (t < 1) {
3855             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3856                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3857         }
3858         return a * Math.pow(2, -10 * (t -= 1)) *
3859                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3860     },
3861
3862
3863
3864     backIn: function (t, b, c, d, s) {
3865         if (typeof s == 'undefined') {
3866             s = 1.70158;
3867         }
3868         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3869     },
3870
3871
3872     backOut: function (t, b, c, d, s) {
3873         if (typeof s == 'undefined') {
3874             s = 1.70158;
3875         }
3876         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3877     },
3878
3879
3880     backBoth: function (t, b, c, d, s) {
3881         if (typeof s == 'undefined') {
3882             s = 1.70158;
3883         }
3884
3885         if ((t /= d / 2 ) < 1) {
3886             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3887         }
3888         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3889     },
3890
3891
3892     bounceIn: function (t, b, c, d) {
3893         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3894     },
3895
3896
3897     bounceOut: function (t, b, c, d) {
3898         if ((t /= d) < (1 / 2.75)) {
3899             return c * (7.5625 * t * t) + b;
3900         } else if (t < (2 / 2.75)) {
3901             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3902         } else if (t < (2.5 / 2.75)) {
3903             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3904         }
3905         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3906     },
3907
3908
3909     bounceBoth: function (t, b, c, d) {
3910         if (t < d / 2) {
3911             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3912         }
3913         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3914     }
3915 };/*
3916  * Portions of this file are based on pieces of Yahoo User Interface Library
3917  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3918  * YUI licensed under the BSD License:
3919  * http://developer.yahoo.net/yui/license.txt
3920  * <script type="text/javascript">
3921  *
3922  */
3923     (function() {
3924         Roo.lib.Motion = function(el, attributes, duration, method) {
3925             if (el) {
3926                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3927             }
3928         };
3929
3930         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3931
3932
3933         var Y = Roo.lib;
3934         var superclass = Y.Motion.superclass;
3935         var proto = Y.Motion.prototype;
3936
3937         proto.toString = function() {
3938             var el = this.getEl();
3939             var id = el.id || el.tagName;
3940             return ("Motion " + id);
3941         };
3942
3943         proto.patterns.points = /^points$/i;
3944
3945         proto.setAttribute = function(attr, val, unit) {
3946             if (this.patterns.points.test(attr)) {
3947                 unit = unit || 'px';
3948                 superclass.setAttribute.call(this, 'left', val[0], unit);
3949                 superclass.setAttribute.call(this, 'top', val[1], unit);
3950             } else {
3951                 superclass.setAttribute.call(this, attr, val, unit);
3952             }
3953         };
3954
3955         proto.getAttribute = function(attr) {
3956             if (this.patterns.points.test(attr)) {
3957                 var val = [
3958                         superclass.getAttribute.call(this, 'left'),
3959                         superclass.getAttribute.call(this, 'top')
3960                         ];
3961             } else {
3962                 val = superclass.getAttribute.call(this, attr);
3963             }
3964
3965             return val;
3966         };
3967
3968         proto.doMethod = function(attr, start, end) {
3969             var val = null;
3970
3971             if (this.patterns.points.test(attr)) {
3972                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3973                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3974             } else {
3975                 val = superclass.doMethod.call(this, attr, start, end);
3976             }
3977             return val;
3978         };
3979
3980         proto.setRuntimeAttribute = function(attr) {
3981             if (this.patterns.points.test(attr)) {
3982                 var el = this.getEl();
3983                 var attributes = this.attributes;
3984                 var start;
3985                 var control = attributes['points']['control'] || [];
3986                 var end;
3987                 var i, len;
3988
3989                 if (control.length > 0 && !(control[0] instanceof Array)) {
3990                     control = [control];
3991                 } else {
3992                     var tmp = [];
3993                     for (i = 0,len = control.length; i < len; ++i) {
3994                         tmp[i] = control[i];
3995                     }
3996                     control = tmp;
3997                 }
3998
3999                 Roo.fly(el).position();
4000
4001                 if (isset(attributes['points']['from'])) {
4002                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4003                 }
4004                 else {
4005                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4006                 }
4007
4008                 start = this.getAttribute('points');
4009
4010
4011                 if (isset(attributes['points']['to'])) {
4012                     end = translateValues.call(this, attributes['points']['to'], start);
4013
4014                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4015                     for (i = 0,len = control.length; i < len; ++i) {
4016                         control[i] = translateValues.call(this, control[i], start);
4017                     }
4018
4019
4020                 } else if (isset(attributes['points']['by'])) {
4021                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4022
4023                     for (i = 0,len = control.length; i < len; ++i) {
4024                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4025                     }
4026                 }
4027
4028                 this.runtimeAttributes[attr] = [start];
4029
4030                 if (control.length > 0) {
4031                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4032                 }
4033
4034                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4035             }
4036             else {
4037                 superclass.setRuntimeAttribute.call(this, attr);
4038             }
4039         };
4040
4041         var translateValues = function(val, start) {
4042             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4043             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4044
4045             return val;
4046         };
4047
4048         var isset = function(prop) {
4049             return (typeof prop !== 'undefined');
4050         };
4051     })();
4052 /*
4053  * Portions of this file are based on pieces of Yahoo User Interface Library
4054  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4055  * YUI licensed under the BSD License:
4056  * http://developer.yahoo.net/yui/license.txt
4057  * <script type="text/javascript">
4058  *
4059  */
4060     (function() {
4061         Roo.lib.Scroll = function(el, attributes, duration, method) {
4062             if (el) {
4063                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4064             }
4065         };
4066
4067         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4068
4069
4070         var Y = Roo.lib;
4071         var superclass = Y.Scroll.superclass;
4072         var proto = Y.Scroll.prototype;
4073
4074         proto.toString = function() {
4075             var el = this.getEl();
4076             var id = el.id || el.tagName;
4077             return ("Scroll " + id);
4078         };
4079
4080         proto.doMethod = function(attr, start, end) {
4081             var val = null;
4082
4083             if (attr == 'scroll') {
4084                 val = [
4085                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4086                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4087                         ];
4088
4089             } else {
4090                 val = superclass.doMethod.call(this, attr, start, end);
4091             }
4092             return val;
4093         };
4094
4095         proto.getAttribute = function(attr) {
4096             var val = null;
4097             var el = this.getEl();
4098
4099             if (attr == 'scroll') {
4100                 val = [ el.scrollLeft, el.scrollTop ];
4101             } else {
4102                 val = superclass.getAttribute.call(this, attr);
4103             }
4104
4105             return val;
4106         };
4107
4108         proto.setAttribute = function(attr, val, unit) {
4109             var el = this.getEl();
4110
4111             if (attr == 'scroll') {
4112                 el.scrollLeft = val[0];
4113                 el.scrollTop = val[1];
4114             } else {
4115                 superclass.setAttribute.call(this, attr, val, unit);
4116             }
4117         };
4118     })();
4119 /*
4120  * Based on:
4121  * Ext JS Library 1.1.1
4122  * Copyright(c) 2006-2007, Ext JS, LLC.
4123  *
4124  * Originally Released Under LGPL - original licence link has changed is not relivant.
4125  *
4126  * Fork - LGPL
4127  * <script type="text/javascript">
4128  */
4129
4130
4131 // nasty IE9 hack - what a pile of crap that is..
4132
4133  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4134     Range.prototype.createContextualFragment = function (html) {
4135         var doc = window.document;
4136         var container = doc.createElement("div");
4137         container.innerHTML = html;
4138         var frag = doc.createDocumentFragment(), n;
4139         while ((n = container.firstChild)) {
4140             frag.appendChild(n);
4141         }
4142         return frag;
4143     };
4144 }
4145
4146 /**
4147  * @class Roo.DomHelper
4148  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4149  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4150  * @singleton
4151  */
4152 Roo.DomHelper = function(){
4153     var tempTableEl = null;
4154     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4155     var tableRe = /^table|tbody|tr|td$/i;
4156     var xmlns = {};
4157     // build as innerHTML where available
4158     /** @ignore */
4159     var createHtml = function(o){
4160         if(typeof o == 'string'){
4161             return o;
4162         }
4163         var b = "";
4164         if(!o.tag){
4165             o.tag = "div";
4166         }
4167         b += "<" + o.tag;
4168         for(var attr in o){
4169             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4170             if(attr == "style"){
4171                 var s = o["style"];
4172                 if(typeof s == "function"){
4173                     s = s.call();
4174                 }
4175                 if(typeof s == "string"){
4176                     b += ' style="' + s + '"';
4177                 }else if(typeof s == "object"){
4178                     b += ' style="';
4179                     for(var key in s){
4180                         if(typeof s[key] != "function"){
4181                             b += key + ":" + s[key] + ";";
4182                         }
4183                     }
4184                     b += '"';
4185                 }
4186             }else{
4187                 if(attr == "cls"){
4188                     b += ' class="' + o["cls"] + '"';
4189                 }else if(attr == "htmlFor"){
4190                     b += ' for="' + o["htmlFor"] + '"';
4191                 }else{
4192                     b += " " + attr + '="' + o[attr] + '"';
4193                 }
4194             }
4195         }
4196         if(emptyTags.test(o.tag)){
4197             b += "/>";
4198         }else{
4199             b += ">";
4200             var cn = o.children || o.cn;
4201             if(cn){
4202                 //http://bugs.kde.org/show_bug.cgi?id=71506
4203                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4204                     for(var i = 0, len = cn.length; i < len; i++) {
4205                         b += createHtml(cn[i], b);
4206                     }
4207                 }else{
4208                     b += createHtml(cn, b);
4209                 }
4210             }
4211             if(o.html){
4212                 b += o.html;
4213             }
4214             b += "</" + o.tag + ">";
4215         }
4216         return b;
4217     };
4218
4219     // build as dom
4220     /** @ignore */
4221     var createDom = function(o, parentNode){
4222          
4223         // defininition craeted..
4224         var ns = false;
4225         if (o.ns && o.ns != 'html') {
4226                
4227             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4228                 xmlns[o.ns] = o.xmlns;
4229                 ns = o.xmlns;
4230             }
4231             if (typeof(xmlns[o.ns]) == 'undefined') {
4232                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4233             }
4234             ns = xmlns[o.ns];
4235         }
4236         
4237         
4238         if (typeof(o) == 'string') {
4239             return parentNode.appendChild(document.createTextNode(o));
4240         }
4241         o.tag = o.tag || div;
4242         if (o.ns && Roo.isIE) {
4243             ns = false;
4244             o.tag = o.ns + ':' + o.tag;
4245             
4246         }
4247         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4248         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4249         for(var attr in o){
4250             
4251             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4252                     attr == "style" || typeof o[attr] == "function") { continue; }
4253                     
4254             if(attr=="cls" && Roo.isIE){
4255                 el.className = o["cls"];
4256             }else{
4257                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4258                 else { 
4259                     el[attr] = o[attr];
4260                 }
4261             }
4262         }
4263         Roo.DomHelper.applyStyles(el, o.style);
4264         var cn = o.children || o.cn;
4265         if(cn){
4266             //http://bugs.kde.org/show_bug.cgi?id=71506
4267              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4268                 for(var i = 0, len = cn.length; i < len; i++) {
4269                     createDom(cn[i], el);
4270                 }
4271             }else{
4272                 createDom(cn, el);
4273             }
4274         }
4275         if(o.html){
4276             el.innerHTML = o.html;
4277         }
4278         if(parentNode){
4279            parentNode.appendChild(el);
4280         }
4281         return el;
4282     };
4283
4284     var ieTable = function(depth, s, h, e){
4285         tempTableEl.innerHTML = [s, h, e].join('');
4286         var i = -1, el = tempTableEl;
4287         while(++i < depth){
4288             el = el.firstChild;
4289         }
4290         return el;
4291     };
4292
4293     // kill repeat to save bytes
4294     var ts = '<table>',
4295         te = '</table>',
4296         tbs = ts+'<tbody>',
4297         tbe = '</tbody>'+te,
4298         trs = tbs + '<tr>',
4299         tre = '</tr>'+tbe;
4300
4301     /**
4302      * @ignore
4303      * Nasty code for IE's broken table implementation
4304      */
4305     var insertIntoTable = function(tag, where, el, html){
4306         if(!tempTableEl){
4307             tempTableEl = document.createElement('div');
4308         }
4309         var node;
4310         var before = null;
4311         if(tag == 'td'){
4312             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4313                 return;
4314             }
4315             if(where == 'beforebegin'){
4316                 before = el;
4317                 el = el.parentNode;
4318             } else{
4319                 before = el.nextSibling;
4320                 el = el.parentNode;
4321             }
4322             node = ieTable(4, trs, html, tre);
4323         }
4324         else if(tag == 'tr'){
4325             if(where == 'beforebegin'){
4326                 before = el;
4327                 el = el.parentNode;
4328                 node = ieTable(3, tbs, html, tbe);
4329             } else if(where == 'afterend'){
4330                 before = el.nextSibling;
4331                 el = el.parentNode;
4332                 node = ieTable(3, tbs, html, tbe);
4333             } else{ // INTO a TR
4334                 if(where == 'afterbegin'){
4335                     before = el.firstChild;
4336                 }
4337                 node = ieTable(4, trs, html, tre);
4338             }
4339         } else if(tag == 'tbody'){
4340             if(where == 'beforebegin'){
4341                 before = el;
4342                 el = el.parentNode;
4343                 node = ieTable(2, ts, html, te);
4344             } else if(where == 'afterend'){
4345                 before = el.nextSibling;
4346                 el = el.parentNode;
4347                 node = ieTable(2, ts, html, te);
4348             } else{
4349                 if(where == 'afterbegin'){
4350                     before = el.firstChild;
4351                 }
4352                 node = ieTable(3, tbs, html, tbe);
4353             }
4354         } else{ // TABLE
4355             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4356                 return;
4357             }
4358             if(where == 'afterbegin'){
4359                 before = el.firstChild;
4360             }
4361             node = ieTable(2, ts, html, te);
4362         }
4363         el.insertBefore(node, before);
4364         return node;
4365     };
4366
4367     return {
4368     /** True to force the use of DOM instead of html fragments @type Boolean */
4369     useDom : false,
4370
4371     /**
4372      * Returns the markup for the passed Element(s) config
4373      * @param {Object} o The Dom object spec (and children)
4374      * @return {String}
4375      */
4376     markup : function(o){
4377         return createHtml(o);
4378     },
4379
4380     /**
4381      * Applies a style specification to an element
4382      * @param {String/HTMLElement} el The element to apply styles to
4383      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4384      * a function which returns such a specification.
4385      */
4386     applyStyles : function(el, styles){
4387         if(styles){
4388            el = Roo.fly(el);
4389            if(typeof styles == "string"){
4390                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4391                var matches;
4392                while ((matches = re.exec(styles)) != null){
4393                    el.setStyle(matches[1], matches[2]);
4394                }
4395            }else if (typeof styles == "object"){
4396                for (var style in styles){
4397                   el.setStyle(style, styles[style]);
4398                }
4399            }else if (typeof styles == "function"){
4400                 Roo.DomHelper.applyStyles(el, styles.call());
4401            }
4402         }
4403     },
4404
4405     /**
4406      * Inserts an HTML fragment into the Dom
4407      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4408      * @param {HTMLElement} el The context element
4409      * @param {String} html The HTML fragmenet
4410      * @return {HTMLElement} The new node
4411      */
4412     insertHtml : function(where, el, html){
4413         where = where.toLowerCase();
4414         if(el.insertAdjacentHTML){
4415             if(tableRe.test(el.tagName)){
4416                 var rs;
4417                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4418                     return rs;
4419                 }
4420             }
4421             switch(where){
4422                 case "beforebegin":
4423                     el.insertAdjacentHTML('BeforeBegin', html);
4424                     return el.previousSibling;
4425                 case "afterbegin":
4426                     el.insertAdjacentHTML('AfterBegin', html);
4427                     return el.firstChild;
4428                 case "beforeend":
4429                     el.insertAdjacentHTML('BeforeEnd', html);
4430                     return el.lastChild;
4431                 case "afterend":
4432                     el.insertAdjacentHTML('AfterEnd', html);
4433                     return el.nextSibling;
4434             }
4435             throw 'Illegal insertion point -> "' + where + '"';
4436         }
4437         var range = el.ownerDocument.createRange();
4438         var frag;
4439         switch(where){
4440              case "beforebegin":
4441                 range.setStartBefore(el);
4442                 frag = range.createContextualFragment(html);
4443                 el.parentNode.insertBefore(frag, el);
4444                 return el.previousSibling;
4445              case "afterbegin":
4446                 if(el.firstChild){
4447                     range.setStartBefore(el.firstChild);
4448                     frag = range.createContextualFragment(html);
4449                     el.insertBefore(frag, el.firstChild);
4450                     return el.firstChild;
4451                 }else{
4452                     el.innerHTML = html;
4453                     return el.firstChild;
4454                 }
4455             case "beforeend":
4456                 if(el.lastChild){
4457                     range.setStartAfter(el.lastChild);
4458                     frag = range.createContextualFragment(html);
4459                     el.appendChild(frag);
4460                     return el.lastChild;
4461                 }else{
4462                     el.innerHTML = html;
4463                     return el.lastChild;
4464                 }
4465             case "afterend":
4466                 range.setStartAfter(el);
4467                 frag = range.createContextualFragment(html);
4468                 el.parentNode.insertBefore(frag, el.nextSibling);
4469                 return el.nextSibling;
4470             }
4471             throw 'Illegal insertion point -> "' + where + '"';
4472     },
4473
4474     /**
4475      * Creates new Dom element(s) and inserts them before el
4476      * @param {String/HTMLElement/Element} el The context element
4477      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4478      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4479      * @return {HTMLElement/Roo.Element} The new node
4480      */
4481     insertBefore : function(el, o, returnElement){
4482         return this.doInsert(el, o, returnElement, "beforeBegin");
4483     },
4484
4485     /**
4486      * Creates new Dom element(s) and inserts them after el
4487      * @param {String/HTMLElement/Element} el The context element
4488      * @param {Object} o The Dom object spec (and children)
4489      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490      * @return {HTMLElement/Roo.Element} The new node
4491      */
4492     insertAfter : function(el, o, returnElement){
4493         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4494     },
4495
4496     /**
4497      * Creates new Dom element(s) and inserts them as the first child of el
4498      * @param {String/HTMLElement/Element} el The context element
4499      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4500      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4501      * @return {HTMLElement/Roo.Element} The new node
4502      */
4503     insertFirst : function(el, o, returnElement){
4504         return this.doInsert(el, o, returnElement, "afterBegin");
4505     },
4506
4507     // private
4508     doInsert : function(el, o, returnElement, pos, sibling){
4509         el = Roo.getDom(el);
4510         var newNode;
4511         if(this.useDom || o.ns){
4512             newNode = createDom(o, null);
4513             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4514         }else{
4515             var html = createHtml(o);
4516             newNode = this.insertHtml(pos, el, html);
4517         }
4518         return returnElement ? Roo.get(newNode, true) : newNode;
4519     },
4520
4521     /**
4522      * Creates new Dom element(s) and appends them to el
4523      * @param {String/HTMLElement/Element} el The context element
4524      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526      * @return {HTMLElement/Roo.Element} The new node
4527      */
4528     append : function(el, o, returnElement){
4529         el = Roo.getDom(el);
4530         var newNode;
4531         if(this.useDom || o.ns){
4532             newNode = createDom(o, null);
4533             el.appendChild(newNode);
4534         }else{
4535             var html = createHtml(o);
4536             newNode = this.insertHtml("beforeEnd", el, html);
4537         }
4538         return returnElement ? Roo.get(newNode, true) : newNode;
4539     },
4540
4541     /**
4542      * Creates new Dom element(s) and overwrites the contents of el with them
4543      * @param {String/HTMLElement/Element} el The context element
4544      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4545      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4546      * @return {HTMLElement/Roo.Element} The new node
4547      */
4548     overwrite : function(el, o, returnElement){
4549         el = Roo.getDom(el);
4550         if (o.ns) {
4551           
4552             while (el.childNodes.length) {
4553                 el.removeChild(el.firstChild);
4554             }
4555             createDom(o, el);
4556         } else {
4557             el.innerHTML = createHtml(o);   
4558         }
4559         
4560         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4561     },
4562
4563     /**
4564      * Creates a new Roo.DomHelper.Template from the Dom object spec
4565      * @param {Object} o The Dom object spec (and children)
4566      * @return {Roo.DomHelper.Template} The new template
4567      */
4568     createTemplate : function(o){
4569         var html = createHtml(o);
4570         return new Roo.Template(html);
4571     }
4572     };
4573 }();
4574 /*
4575  * Based on:
4576  * Ext JS Library 1.1.1
4577  * Copyright(c) 2006-2007, Ext JS, LLC.
4578  *
4579  * Originally Released Under LGPL - original licence link has changed is not relivant.
4580  *
4581  * Fork - LGPL
4582  * <script type="text/javascript">
4583  */
4584  
4585 /**
4586 * @class Roo.Template
4587 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4588 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4589 * Usage:
4590 <pre><code>
4591 var t = new Roo.Template({
4592     html :  '&lt;div name="{id}"&gt;' + 
4593         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4594         '&lt;/div&gt;',
4595     myformat: function (value, allValues) {
4596         return 'XX' + value;
4597     }
4598 });
4599 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4600 </code></pre>
4601 * For more information see this blog post with examples:
4602 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4603      - Create Elements using DOM, HTML fragments and Templates</a>. 
4604 * @constructor
4605 * @param {Object} cfg - Configuration object.
4606 */
4607 Roo.Template = function(cfg){
4608     // BC!
4609     if(cfg instanceof Array){
4610         cfg = cfg.join("");
4611     }else if(arguments.length > 1){
4612         cfg = Array.prototype.join.call(arguments, "");
4613     }
4614     
4615     
4616     if (typeof(cfg) == 'object') {
4617         Roo.apply(this,cfg)
4618     } else {
4619         // bc
4620         this.html = cfg;
4621     }
4622     if (this.url) {
4623         this.load();
4624     }
4625     
4626 };
4627 Roo.Template.prototype = {
4628     
4629     /**
4630      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4631      *                    it should be fixed so that template is observable...
4632      */
4633     url : false,
4634     /**
4635      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4636      */
4637     html : '',
4638     /**
4639      * Returns an HTML fragment of this template with the specified values applied.
4640      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4641      * @return {String} The HTML fragment
4642      */
4643     applyTemplate : function(values){
4644         try {
4645            
4646             if(this.compiled){
4647                 return this.compiled(values);
4648             }
4649             var useF = this.disableFormats !== true;
4650             var fm = Roo.util.Format, tpl = this;
4651             var fn = function(m, name, format, args){
4652                 if(format && useF){
4653                     if(format.substr(0, 5) == "this."){
4654                         return tpl.call(format.substr(5), values[name], values);
4655                     }else{
4656                         if(args){
4657                             // quoted values are required for strings in compiled templates, 
4658                             // but for non compiled we need to strip them
4659                             // quoted reversed for jsmin
4660                             var re = /^\s*['"](.*)["']\s*$/;
4661                             args = args.split(',');
4662                             for(var i = 0, len = args.length; i < len; i++){
4663                                 args[i] = args[i].replace(re, "$1");
4664                             }
4665                             args = [values[name]].concat(args);
4666                         }else{
4667                             args = [values[name]];
4668                         }
4669                         return fm[format].apply(fm, args);
4670                     }
4671                 }else{
4672                     return values[name] !== undefined ? values[name] : "";
4673                 }
4674             };
4675             return this.html.replace(this.re, fn);
4676         } catch (e) {
4677             Roo.log(e);
4678             throw e;
4679         }
4680          
4681     },
4682     
4683     loading : false,
4684       
4685     load : function ()
4686     {
4687          
4688         if (this.loading) {
4689             return;
4690         }
4691         var _t = this;
4692         
4693         this.loading = true;
4694         this.compiled = false;
4695         
4696         var cx = new Roo.data.Connection();
4697         cx.request({
4698             url : this.url,
4699             method : 'GET',
4700             success : function (response) {
4701                 _t.loading = false;
4702                 _t.html = response.responseText;
4703                 _t.url = false;
4704                 _t.compile();
4705              },
4706             failure : function(response) {
4707                 Roo.log("Template failed to load from " + _t.url);
4708                 _t.loading = false;
4709             }
4710         });
4711     },
4712
4713     /**
4714      * Sets the HTML used as the template and optionally compiles it.
4715      * @param {String} html
4716      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4717      * @return {Roo.Template} this
4718      */
4719     set : function(html, compile){
4720         this.html = html;
4721         this.compiled = null;
4722         if(compile){
4723             this.compile();
4724         }
4725         return this;
4726     },
4727     
4728     /**
4729      * True to disable format functions (defaults to false)
4730      * @type Boolean
4731      */
4732     disableFormats : false,
4733     
4734     /**
4735     * The regular expression used to match template variables 
4736     * @type RegExp
4737     * @property 
4738     */
4739     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4740     
4741     /**
4742      * Compiles the template into an internal function, eliminating the RegEx overhead.
4743      * @return {Roo.Template} this
4744      */
4745     compile : function(){
4746         var fm = Roo.util.Format;
4747         var useF = this.disableFormats !== true;
4748         var sep = Roo.isGecko ? "+" : ",";
4749         var fn = function(m, name, format, args){
4750             if(format && useF){
4751                 args = args ? ',' + args : "";
4752                 if(format.substr(0, 5) != "this."){
4753                     format = "fm." + format + '(';
4754                 }else{
4755                     format = 'this.call("'+ format.substr(5) + '", ';
4756                     args = ", values";
4757                 }
4758             }else{
4759                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4760             }
4761             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4762         };
4763         var body;
4764         // branched to use + in gecko and [].join() in others
4765         if(Roo.isGecko){
4766             body = "this.compiled = function(values){ return '" +
4767                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4768                     "';};";
4769         }else{
4770             body = ["this.compiled = function(values){ return ['"];
4771             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4772             body.push("'].join('');};");
4773             body = body.join('');
4774         }
4775         /**
4776          * eval:var:values
4777          * eval:var:fm
4778          */
4779         eval(body);
4780         return this;
4781     },
4782     
4783     // private function used to call members
4784     call : function(fnName, value, allValues){
4785         return this[fnName](value, allValues);
4786     },
4787     
4788     /**
4789      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4790      * @param {String/HTMLElement/Roo.Element} el The context element
4791      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4792      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793      * @return {HTMLElement/Roo.Element} The new node or Element
4794      */
4795     insertFirst: function(el, values, returnElement){
4796         return this.doInsert('afterBegin', el, values, returnElement);
4797     },
4798
4799     /**
4800      * Applies the supplied values to the template and inserts the new node(s) before el.
4801      * @param {String/HTMLElement/Roo.Element} el The context element
4802      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4803      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4804      * @return {HTMLElement/Roo.Element} The new node or Element
4805      */
4806     insertBefore: function(el, values, returnElement){
4807         return this.doInsert('beforeBegin', el, values, returnElement);
4808     },
4809
4810     /**
4811      * Applies the supplied values to the template and inserts the new node(s) after el.
4812      * @param {String/HTMLElement/Roo.Element} el The context element
4813      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4814      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4815      * @return {HTMLElement/Roo.Element} The new node or Element
4816      */
4817     insertAfter : function(el, values, returnElement){
4818         return this.doInsert('afterEnd', el, values, returnElement);
4819     },
4820     
4821     /**
4822      * Applies the supplied values to the template and appends the new node(s) to el.
4823      * @param {String/HTMLElement/Roo.Element} el The context element
4824      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4825      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4826      * @return {HTMLElement/Roo.Element} The new node or Element
4827      */
4828     append : function(el, values, returnElement){
4829         return this.doInsert('beforeEnd', el, values, returnElement);
4830     },
4831
4832     doInsert : function(where, el, values, returnEl){
4833         el = Roo.getDom(el);
4834         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4835         return returnEl ? Roo.get(newNode, true) : newNode;
4836     },
4837
4838     /**
4839      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4840      * @param {String/HTMLElement/Roo.Element} el The context element
4841      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4842      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4843      * @return {HTMLElement/Roo.Element} The new node or Element
4844      */
4845     overwrite : function(el, values, returnElement){
4846         el = Roo.getDom(el);
4847         el.innerHTML = this.applyTemplate(values);
4848         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4849     }
4850 };
4851 /**
4852  * Alias for {@link #applyTemplate}
4853  * @method
4854  */
4855 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4856
4857 // backwards compat
4858 Roo.DomHelper.Template = Roo.Template;
4859
4860 /**
4861  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4862  * @param {String/HTMLElement} el A DOM element or its id
4863  * @returns {Roo.Template} The created template
4864  * @static
4865  */
4866 Roo.Template.from = function(el){
4867     el = Roo.getDom(el);
4868     return new Roo.Template(el.value || el.innerHTML);
4869 };/*
4870  * Based on:
4871  * Ext JS Library 1.1.1
4872  * Copyright(c) 2006-2007, Ext JS, LLC.
4873  *
4874  * Originally Released Under LGPL - original licence link has changed is not relivant.
4875  *
4876  * Fork - LGPL
4877  * <script type="text/javascript">
4878  */
4879  
4880
4881 /*
4882  * This is code is also distributed under MIT license for use
4883  * with jQuery and prototype JavaScript libraries.
4884  */
4885 /**
4886  * @class Roo.DomQuery
4887 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4888 <p>
4889 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4890
4891 <p>
4892 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4893 </p>
4894 <h4>Element Selectors:</h4>
4895 <ul class="list">
4896     <li> <b>*</b> any element</li>
4897     <li> <b>E</b> an element with the tag E</li>
4898     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4899     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4900     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4901     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4902 </ul>
4903 <h4>Attribute Selectors:</h4>
4904 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4905 <ul class="list">
4906     <li> <b>E[foo]</b> has an attribute "foo"</li>
4907     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4908     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4909     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4910     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4911     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4912     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4913 </ul>
4914 <h4>Pseudo Classes:</h4>
4915 <ul class="list">
4916     <li> <b>E:first-child</b> E is the first child of its parent</li>
4917     <li> <b>E:last-child</b> E is the last child of its parent</li>
4918     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4919     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4920     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4921     <li> <b>E:only-child</b> E is the only child of its parent</li>
4922     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4923     <li> <b>E:first</b> the first E in the resultset</li>
4924     <li> <b>E:last</b> the last E in the resultset</li>
4925     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4926     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4927     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4928     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4929     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4930     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4931     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4932     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4933     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4934 </ul>
4935 <h4>CSS Value Selectors:</h4>
4936 <ul class="list">
4937     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4938     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4939     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4940     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4941     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4942     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4943 </ul>
4944  * @singleton
4945  */
4946 Roo.DomQuery = function(){
4947     var cache = {}, simpleCache = {}, valueCache = {};
4948     var nonSpace = /\S/;
4949     var trimRe = /^\s+|\s+$/g;
4950     var tplRe = /\{(\d+)\}/g;
4951     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4952     var tagTokenRe = /^(#)?([\w-\*]+)/;
4953     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4954
4955     function child(p, index){
4956         var i = 0;
4957         var n = p.firstChild;
4958         while(n){
4959             if(n.nodeType == 1){
4960                if(++i == index){
4961                    return n;
4962                }
4963             }
4964             n = n.nextSibling;
4965         }
4966         return null;
4967     };
4968
4969     function next(n){
4970         while((n = n.nextSibling) && n.nodeType != 1);
4971         return n;
4972     };
4973
4974     function prev(n){
4975         while((n = n.previousSibling) && n.nodeType != 1);
4976         return n;
4977     };
4978
4979     function children(d){
4980         var n = d.firstChild, ni = -1;
4981             while(n){
4982                 var nx = n.nextSibling;
4983                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4984                     d.removeChild(n);
4985                 }else{
4986                     n.nodeIndex = ++ni;
4987                 }
4988                 n = nx;
4989             }
4990             return this;
4991         };
4992
4993     function byClassName(c, a, v){
4994         if(!v){
4995             return c;
4996         }
4997         var r = [], ri = -1, cn;
4998         for(var i = 0, ci; ci = c[i]; i++){
4999             if((' '+ci.className+' ').indexOf(v) != -1){
5000                 r[++ri] = ci;
5001             }
5002         }
5003         return r;
5004     };
5005
5006     function attrValue(n, attr){
5007         if(!n.tagName && typeof n.length != "undefined"){
5008             n = n[0];
5009         }
5010         if(!n){
5011             return null;
5012         }
5013         if(attr == "for"){
5014             return n.htmlFor;
5015         }
5016         if(attr == "class" || attr == "className"){
5017             return n.className;
5018         }
5019         return n.getAttribute(attr) || n[attr];
5020
5021     };
5022
5023     function getNodes(ns, mode, tagName){
5024         var result = [], ri = -1, cs;
5025         if(!ns){
5026             return result;
5027         }
5028         tagName = tagName || "*";
5029         if(typeof ns.getElementsByTagName != "undefined"){
5030             ns = [ns];
5031         }
5032         if(!mode){
5033             for(var i = 0, ni; ni = ns[i]; i++){
5034                 cs = ni.getElementsByTagName(tagName);
5035                 for(var j = 0, ci; ci = cs[j]; j++){
5036                     result[++ri] = ci;
5037                 }
5038             }
5039         }else if(mode == "/" || mode == ">"){
5040             var utag = tagName.toUpperCase();
5041             for(var i = 0, ni, cn; ni = ns[i]; i++){
5042                 cn = ni.children || ni.childNodes;
5043                 for(var j = 0, cj; cj = cn[j]; j++){
5044                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5045                         result[++ri] = cj;
5046                     }
5047                 }
5048             }
5049         }else if(mode == "+"){
5050             var utag = tagName.toUpperCase();
5051             for(var i = 0, n; n = ns[i]; i++){
5052                 while((n = n.nextSibling) && n.nodeType != 1);
5053                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5054                     result[++ri] = n;
5055                 }
5056             }
5057         }else if(mode == "~"){
5058             for(var i = 0, n; n = ns[i]; i++){
5059                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5060                 if(n){
5061                     result[++ri] = n;
5062                 }
5063             }
5064         }
5065         return result;
5066     };
5067
5068     function concat(a, b){
5069         if(b.slice){
5070             return a.concat(b);
5071         }
5072         for(var i = 0, l = b.length; i < l; i++){
5073             a[a.length] = b[i];
5074         }
5075         return a;
5076     }
5077
5078     function byTag(cs, tagName){
5079         if(cs.tagName || cs == document){
5080             cs = [cs];
5081         }
5082         if(!tagName){
5083             return cs;
5084         }
5085         var r = [], ri = -1;
5086         tagName = tagName.toLowerCase();
5087         for(var i = 0, ci; ci = cs[i]; i++){
5088             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089                 r[++ri] = ci;
5090             }
5091         }
5092         return r;
5093     };
5094
5095     function byId(cs, attr, id){
5096         if(cs.tagName || cs == document){
5097             cs = [cs];
5098         }
5099         if(!id){
5100             return cs;
5101         }
5102         var r = [], ri = -1;
5103         for(var i = 0,ci; ci = cs[i]; i++){
5104             if(ci && ci.id == id){
5105                 r[++ri] = ci;
5106                 return r;
5107             }
5108         }
5109         return r;
5110     };
5111
5112     function byAttribute(cs, attr, value, op, custom){
5113         var r = [], ri = -1, st = custom=="{";
5114         var f = Roo.DomQuery.operators[op];
5115         for(var i = 0, ci; ci = cs[i]; i++){
5116             var a;
5117             if(st){
5118                 a = Roo.DomQuery.getStyle(ci, attr);
5119             }
5120             else if(attr == "class" || attr == "className"){
5121                 a = ci.className;
5122             }else if(attr == "for"){
5123                 a = ci.htmlFor;
5124             }else if(attr == "href"){
5125                 a = ci.getAttribute("href", 2);
5126             }else{
5127                 a = ci.getAttribute(attr);
5128             }
5129             if((f && f(a, value)) || (!f && a)){
5130                 r[++ri] = ci;
5131             }
5132         }
5133         return r;
5134     };
5135
5136     function byPseudo(cs, name, value){
5137         return Roo.DomQuery.pseudos[name](cs, value);
5138     };
5139
5140     // This is for IE MSXML which does not support expandos.
5141     // IE runs the same speed using setAttribute, however FF slows way down
5142     // and Safari completely fails so they need to continue to use expandos.
5143     var isIE = window.ActiveXObject ? true : false;
5144
5145     // this eval is stop the compressor from
5146     // renaming the variable to something shorter
5147     
5148     /** eval:var:batch */
5149     var batch = 30803; 
5150
5151     var key = 30803;
5152
5153     function nodupIEXml(cs){
5154         var d = ++key;
5155         cs[0].setAttribute("_nodup", d);
5156         var r = [cs[0]];
5157         for(var i = 1, len = cs.length; i < len; i++){
5158             var c = cs[i];
5159             if(!c.getAttribute("_nodup") != d){
5160                 c.setAttribute("_nodup", d);
5161                 r[r.length] = c;
5162             }
5163         }
5164         for(var i = 0, len = cs.length; i < len; i++){
5165             cs[i].removeAttribute("_nodup");
5166         }
5167         return r;
5168     }
5169
5170     function nodup(cs){
5171         if(!cs){
5172             return [];
5173         }
5174         var len = cs.length, c, i, r = cs, cj, ri = -1;
5175         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5176             return cs;
5177         }
5178         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5179             return nodupIEXml(cs);
5180         }
5181         var d = ++key;
5182         cs[0]._nodup = d;
5183         for(i = 1; c = cs[i]; i++){
5184             if(c._nodup != d){
5185                 c._nodup = d;
5186             }else{
5187                 r = [];
5188                 for(var j = 0; j < i; j++){
5189                     r[++ri] = cs[j];
5190                 }
5191                 for(j = i+1; cj = cs[j]; j++){
5192                     if(cj._nodup != d){
5193                         cj._nodup = d;
5194                         r[++ri] = cj;
5195                     }
5196                 }
5197                 return r;
5198             }
5199         }
5200         return r;
5201     }
5202
5203     function quickDiffIEXml(c1, c2){
5204         var d = ++key;
5205         for(var i = 0, len = c1.length; i < len; i++){
5206             c1[i].setAttribute("_qdiff", d);
5207         }
5208         var r = [];
5209         for(var i = 0, len = c2.length; i < len; i++){
5210             if(c2[i].getAttribute("_qdiff") != d){
5211                 r[r.length] = c2[i];
5212             }
5213         }
5214         for(var i = 0, len = c1.length; i < len; i++){
5215            c1[i].removeAttribute("_qdiff");
5216         }
5217         return r;
5218     }
5219
5220     function quickDiff(c1, c2){
5221         var len1 = c1.length;
5222         if(!len1){
5223             return c2;
5224         }
5225         if(isIE && c1[0].selectSingleNode){
5226             return quickDiffIEXml(c1, c2);
5227         }
5228         var d = ++key;
5229         for(var i = 0; i < len1; i++){
5230             c1[i]._qdiff = d;
5231         }
5232         var r = [];
5233         for(var i = 0, len = c2.length; i < len; i++){
5234             if(c2[i]._qdiff != d){
5235                 r[r.length] = c2[i];
5236             }
5237         }
5238         return r;
5239     }
5240
5241     function quickId(ns, mode, root, id){
5242         if(ns == root){
5243            var d = root.ownerDocument || root;
5244            return d.getElementById(id);
5245         }
5246         ns = getNodes(ns, mode, "*");
5247         return byId(ns, null, id);
5248     }
5249
5250     return {
5251         getStyle : function(el, name){
5252             return Roo.fly(el).getStyle(name);
5253         },
5254         /**
5255          * Compiles a selector/xpath query into a reusable function. The returned function
5256          * takes one parameter "root" (optional), which is the context node from where the query should start.
5257          * @param {String} selector The selector/xpath query
5258          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5259          * @return {Function}
5260          */
5261         compile : function(path, type){
5262             type = type || "select";
5263             
5264             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5265             var q = path, mode, lq;
5266             var tk = Roo.DomQuery.matchers;
5267             var tklen = tk.length;
5268             var mm;
5269
5270             // accept leading mode switch
5271             var lmode = q.match(modeRe);
5272             if(lmode && lmode[1]){
5273                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5274                 q = q.replace(lmode[1], "");
5275             }
5276             // strip leading slashes
5277             while(path.substr(0, 1)=="/"){
5278                 path = path.substr(1);
5279             }
5280
5281             while(q && lq != q){
5282                 lq = q;
5283                 var tm = q.match(tagTokenRe);
5284                 if(type == "select"){
5285                     if(tm){
5286                         if(tm[1] == "#"){
5287                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5288                         }else{
5289                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5290                         }
5291                         q = q.replace(tm[0], "");
5292                     }else if(q.substr(0, 1) != '@'){
5293                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5294                     }
5295                 }else{
5296                     if(tm){
5297                         if(tm[1] == "#"){
5298                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5299                         }else{
5300                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5301                         }
5302                         q = q.replace(tm[0], "");
5303                     }
5304                 }
5305                 while(!(mm = q.match(modeRe))){
5306                     var matched = false;
5307                     for(var j = 0; j < tklen; j++){
5308                         var t = tk[j];
5309                         var m = q.match(t.re);
5310                         if(m){
5311                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5312                                                     return m[i];
5313                                                 });
5314                             q = q.replace(m[0], "");
5315                             matched = true;
5316                             break;
5317                         }
5318                     }
5319                     // prevent infinite loop on bad selector
5320                     if(!matched){
5321                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5322                     }
5323                 }
5324                 if(mm[1]){
5325                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5326                     q = q.replace(mm[1], "");
5327                 }
5328             }
5329             fn[fn.length] = "return nodup(n);\n}";
5330             
5331              /** 
5332               * list of variables that need from compression as they are used by eval.
5333              *  eval:var:batch 
5334              *  eval:var:nodup
5335              *  eval:var:byTag
5336              *  eval:var:ById
5337              *  eval:var:getNodes
5338              *  eval:var:quickId
5339              *  eval:var:mode
5340              *  eval:var:root
5341              *  eval:var:n
5342              *  eval:var:byClassName
5343              *  eval:var:byPseudo
5344              *  eval:var:byAttribute
5345              *  eval:var:attrValue
5346              * 
5347              **/ 
5348             eval(fn.join(""));
5349             return f;
5350         },
5351
5352         /**
5353          * Selects a group of elements.
5354          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5355          * @param {Node} root (optional) The start of the query (defaults to document).
5356          * @return {Array}
5357          */
5358         select : function(path, root, type){
5359             if(!root || root == document){
5360                 root = document;
5361             }
5362             if(typeof root == "string"){
5363                 root = document.getElementById(root);
5364             }
5365             var paths = path.split(",");
5366             var results = [];
5367             for(var i = 0, len = paths.length; i < len; i++){
5368                 var p = paths[i].replace(trimRe, "");
5369                 if(!cache[p]){
5370                     cache[p] = Roo.DomQuery.compile(p);
5371                     if(!cache[p]){
5372                         throw p + " is not a valid selector";
5373                     }
5374                 }
5375                 var result = cache[p](root);
5376                 if(result && result != document){
5377                     results = results.concat(result);
5378                 }
5379             }
5380             if(paths.length > 1){
5381                 return nodup(results);
5382             }
5383             return results;
5384         },
5385
5386         /**
5387          * Selects a single element.
5388          * @param {String} selector The selector/xpath query
5389          * @param {Node} root (optional) The start of the query (defaults to document).
5390          * @return {Element}
5391          */
5392         selectNode : function(path, root){
5393             return Roo.DomQuery.select(path, root)[0];
5394         },
5395
5396         /**
5397          * Selects the value of a node, optionally replacing null with the defaultValue.
5398          * @param {String} selector The selector/xpath query
5399          * @param {Node} root (optional) The start of the query (defaults to document).
5400          * @param {String} defaultValue
5401          */
5402         selectValue : function(path, root, defaultValue){
5403             path = path.replace(trimRe, "");
5404             if(!valueCache[path]){
5405                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5406             }
5407             var n = valueCache[path](root);
5408             n = n[0] ? n[0] : n;
5409             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5410             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5411         },
5412
5413         /**
5414          * Selects the value of a node, parsing integers and floats.
5415          * @param {String} selector The selector/xpath query
5416          * @param {Node} root (optional) The start of the query (defaults to document).
5417          * @param {Number} defaultValue
5418          * @return {Number}
5419          */
5420         selectNumber : function(path, root, defaultValue){
5421             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5422             return parseFloat(v);
5423         },
5424
5425         /**
5426          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5427          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5428          * @param {String} selector The simple selector to test
5429          * @return {Boolean}
5430          */
5431         is : function(el, ss){
5432             if(typeof el == "string"){
5433                 el = document.getElementById(el);
5434             }
5435             var isArray = (el instanceof Array);
5436             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5437             return isArray ? (result.length == el.length) : (result.length > 0);
5438         },
5439
5440         /**
5441          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5442          * @param {Array} el An array of elements to filter
5443          * @param {String} selector The simple selector to test
5444          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5445          * the selector instead of the ones that match
5446          * @return {Array}
5447          */
5448         filter : function(els, ss, nonMatches){
5449             ss = ss.replace(trimRe, "");
5450             if(!simpleCache[ss]){
5451                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5452             }
5453             var result = simpleCache[ss](els);
5454             return nonMatches ? quickDiff(result, els) : result;
5455         },
5456
5457         /**
5458          * Collection of matching regular expressions and code snippets.
5459          */
5460         matchers : [{
5461                 re: /^\.([\w-]+)/,
5462                 select: 'n = byClassName(n, null, " {1} ");'
5463             }, {
5464                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5465                 select: 'n = byPseudo(n, "{1}", "{2}");'
5466             },{
5467                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5468                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5469             }, {
5470                 re: /^#([\w-]+)/,
5471                 select: 'n = byId(n, null, "{1}");'
5472             },{
5473                 re: /^@([\w-]+)/,
5474                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5475             }
5476         ],
5477
5478         /**
5479          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5480          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5481          */
5482         operators : {
5483             "=" : function(a, v){
5484                 return a == v;
5485             },
5486             "!=" : function(a, v){
5487                 return a != v;
5488             },
5489             "^=" : function(a, v){
5490                 return a && a.substr(0, v.length) == v;
5491             },
5492             "$=" : function(a, v){
5493                 return a && a.substr(a.length-v.length) == v;
5494             },
5495             "*=" : function(a, v){
5496                 return a && a.indexOf(v) !== -1;
5497             },
5498             "%=" : function(a, v){
5499                 return (a % v) == 0;
5500             },
5501             "|=" : function(a, v){
5502                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5503             },
5504             "~=" : function(a, v){
5505                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5506             }
5507         },
5508
5509         /**
5510          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5511          * and the argument (if any) supplied in the selector.
5512          */
5513         pseudos : {
5514             "first-child" : function(c){
5515                 var r = [], ri = -1, n;
5516                 for(var i = 0, ci; ci = n = c[i]; i++){
5517                     while((n = n.previousSibling) && n.nodeType != 1);
5518                     if(!n){
5519                         r[++ri] = ci;
5520                     }
5521                 }
5522                 return r;
5523             },
5524
5525             "last-child" : function(c){
5526                 var r = [], ri = -1, n;
5527                 for(var i = 0, ci; ci = n = c[i]; i++){
5528                     while((n = n.nextSibling) && n.nodeType != 1);
5529                     if(!n){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "nth-child" : function(c, a) {
5537                 var r = [], ri = -1;
5538                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5539                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5540                 for(var i = 0, n; n = c[i]; i++){
5541                     var pn = n.parentNode;
5542                     if (batch != pn._batch) {
5543                         var j = 0;
5544                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5545                             if(cn.nodeType == 1){
5546                                cn.nodeIndex = ++j;
5547                             }
5548                         }
5549                         pn._batch = batch;
5550                     }
5551                     if (f == 1) {
5552                         if (l == 0 || n.nodeIndex == l){
5553                             r[++ri] = n;
5554                         }
5555                     } else if ((n.nodeIndex + l) % f == 0){
5556                         r[++ri] = n;
5557                     }
5558                 }
5559
5560                 return r;
5561             },
5562
5563             "only-child" : function(c){
5564                 var r = [], ri = -1;;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if(!prev(ci) && !next(ci)){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "empty" : function(c){
5574                 var r = [], ri = -1;
5575                 for(var i = 0, ci; ci = c[i]; i++){
5576                     var cns = ci.childNodes, j = 0, cn, empty = true;
5577                     while(cn = cns[j]){
5578                         ++j;
5579                         if(cn.nodeType == 1 || cn.nodeType == 3){
5580                             empty = false;
5581                             break;
5582                         }
5583                     }
5584                     if(empty){
5585                         r[++ri] = ci;
5586                     }
5587                 }
5588                 return r;
5589             },
5590
5591             "contains" : function(c, v){
5592                 var r = [], ri = -1;
5593                 for(var i = 0, ci; ci = c[i]; i++){
5594                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595                         r[++ri] = ci;
5596                     }
5597                 }
5598                 return r;
5599             },
5600
5601             "nodeValue" : function(c, v){
5602                 var r = [], ri = -1;
5603                 for(var i = 0, ci; ci = c[i]; i++){
5604                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5605                         r[++ri] = ci;
5606                     }
5607                 }
5608                 return r;
5609             },
5610
5611             "checked" : function(c){
5612                 var r = [], ri = -1;
5613                 for(var i = 0, ci; ci = c[i]; i++){
5614                     if(ci.checked == true){
5615                         r[++ri] = ci;
5616                     }
5617                 }
5618                 return r;
5619             },
5620
5621             "not" : function(c, ss){
5622                 return Roo.DomQuery.filter(c, ss, true);
5623             },
5624
5625             "odd" : function(c){
5626                 return this["nth-child"](c, "odd");
5627             },
5628
5629             "even" : function(c){
5630                 return this["nth-child"](c, "even");
5631             },
5632
5633             "nth" : function(c, a){
5634                 return c[a-1] || [];
5635             },
5636
5637             "first" : function(c){
5638                 return c[0] || [];
5639             },
5640
5641             "last" : function(c){
5642                 return c[c.length-1] || [];
5643             },
5644
5645             "has" : function(c, ss){
5646                 var s = Roo.DomQuery.select;
5647                 var r = [], ri = -1;
5648                 for(var i = 0, ci; ci = c[i]; i++){
5649                     if(s(ss, ci).length > 0){
5650                         r[++ri] = ci;
5651                     }
5652                 }
5653                 return r;
5654             },
5655
5656             "next" : function(c, ss){
5657                 var is = Roo.DomQuery.is;
5658                 var r = [], ri = -1;
5659                 for(var i = 0, ci; ci = c[i]; i++){
5660                     var n = next(ci);
5661                     if(n && is(n, ss)){
5662                         r[++ri] = ci;
5663                     }
5664                 }
5665                 return r;
5666             },
5667
5668             "prev" : function(c, ss){
5669                 var is = Roo.DomQuery.is;
5670                 var r = [], ri = -1;
5671                 for(var i = 0, ci; ci = c[i]; i++){
5672                     var n = prev(ci);
5673                     if(n && is(n, ss)){
5674                         r[++ri] = ci;
5675                     }
5676                 }
5677                 return r;
5678             }
5679         }
5680     };
5681 }();
5682
5683 /**
5684  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5685  * @param {String} path The selector/xpath query
5686  * @param {Node} root (optional) The start of the query (defaults to document).
5687  * @return {Array}
5688  * @member Roo
5689  * @method query
5690  */
5691 Roo.query = Roo.DomQuery.select;
5692 /*
5693  * Based on:
5694  * Ext JS Library 1.1.1
5695  * Copyright(c) 2006-2007, Ext JS, LLC.
5696  *
5697  * Originally Released Under LGPL - original licence link has changed is not relivant.
5698  *
5699  * Fork - LGPL
5700  * <script type="text/javascript">
5701  */
5702
5703 /**
5704  * @class Roo.util.Observable
5705  * Base class that provides a common interface for publishing events. Subclasses are expected to
5706  * to have a property "events" with all the events defined.<br>
5707  * For example:
5708  * <pre><code>
5709  Employee = function(name){
5710     this.name = name;
5711     this.addEvents({
5712         "fired" : true,
5713         "quit" : true
5714     });
5715  }
5716  Roo.extend(Employee, Roo.util.Observable);
5717 </code></pre>
5718  * @param {Object} config properties to use (incuding events / listeners)
5719  */
5720
5721 Roo.util.Observable = function(cfg){
5722     
5723     cfg = cfg|| {};
5724     this.addEvents(cfg.events || {});
5725     if (cfg.events) {
5726         delete cfg.events; // make sure
5727     }
5728      
5729     Roo.apply(this, cfg);
5730     
5731     if(this.listeners){
5732         this.on(this.listeners);
5733         delete this.listeners;
5734     }
5735 };
5736 Roo.util.Observable.prototype = {
5737     /** 
5738  * @cfg {Object} listeners  list of events and functions to call for this object, 
5739  * For example :
5740  * <pre><code>
5741     listeners :  { 
5742        'click' : function(e) {
5743            ..... 
5744         } ,
5745         .... 
5746     } 
5747   </code></pre>
5748  */
5749     
5750     
5751     /**
5752      * Fires the specified event with the passed parameters (minus the event name).
5753      * @param {String} eventName
5754      * @param {Object...} args Variable number of parameters are passed to handlers
5755      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5756      */
5757     fireEvent : function(){
5758         var ce = this.events[arguments[0].toLowerCase()];
5759         if(typeof ce == "object"){
5760             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761         }else{
5762             return true;
5763         }
5764     },
5765
5766     // private
5767     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5768
5769     /**
5770      * Appends an event handler to this component
5771      * @param {String}   eventName The type of event to listen for
5772      * @param {Function} handler The method the event invokes
5773      * @param {Object}   scope (optional) The scope in which to execute the handler
5774      * function. The handler function's "this" context.
5775      * @param {Object}   options (optional) An object containing handler configuration
5776      * properties. This may contain any of the following properties:<ul>
5777      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5778      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5779      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5780      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5781      * by the specified number of milliseconds. If the event fires again within that time, the original
5782      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5783      * </ul><br>
5784      * <p>
5785      * <b>Combining Options</b><br>
5786      * Using the options argument, it is possible to combine different types of listeners:<br>
5787      * <br>
5788      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5789                 <pre><code>
5790                 el.on('click', this.onClick, this, {
5791                         single: true,
5792                 delay: 100,
5793                 forumId: 4
5794                 });
5795                 </code></pre>
5796      * <p>
5797      * <b>Attaching multiple handlers in 1 call</b><br>
5798      * The method also allows for a single argument to be passed which is a config object containing properties
5799      * which specify multiple handlers.
5800      * <pre><code>
5801                 el.on({
5802                         'click': {
5803                         fn: this.onClick,
5804                         scope: this,
5805                         delay: 100
5806                 }, 
5807                 'mouseover': {
5808                         fn: this.onMouseOver,
5809                         scope: this
5810                 },
5811                 'mouseout': {
5812                         fn: this.onMouseOut,
5813                         scope: this
5814                 }
5815                 });
5816                 </code></pre>
5817      * <p>
5818      * Or a shorthand syntax which passes the same scope object to all handlers:
5819         <pre><code>
5820                 el.on({
5821                         'click': this.onClick,
5822                 'mouseover': this.onMouseOver,
5823                 'mouseout': this.onMouseOut,
5824                 scope: this
5825                 });
5826                 </code></pre>
5827      */
5828     addListener : function(eventName, fn, scope, o){
5829         if(typeof eventName == "object"){
5830             o = eventName;
5831             for(var e in o){
5832                 if(this.filterOptRe.test(e)){
5833                     continue;
5834                 }
5835                 if(typeof o[e] == "function"){
5836                     // shared options
5837                     this.addListener(e, o[e], o.scope,  o);
5838                 }else{
5839                     // individual options
5840                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5841                 }
5842             }
5843             return;
5844         }
5845         o = (!o || typeof o == "boolean") ? {} : o;
5846         eventName = eventName.toLowerCase();
5847         var ce = this.events[eventName] || true;
5848         if(typeof ce == "boolean"){
5849             ce = new Roo.util.Event(this, eventName);
5850             this.events[eventName] = ce;
5851         }
5852         ce.addListener(fn, scope, o);
5853     },
5854
5855     /**
5856      * Removes a listener
5857      * @param {String}   eventName     The type of event to listen for
5858      * @param {Function} handler        The handler to remove
5859      * @param {Object}   scope  (optional) The scope (this object) for the handler
5860      */
5861     removeListener : function(eventName, fn, scope){
5862         var ce = this.events[eventName.toLowerCase()];
5863         if(typeof ce == "object"){
5864             ce.removeListener(fn, scope);
5865         }
5866     },
5867
5868     /**
5869      * Removes all listeners for this object
5870      */
5871     purgeListeners : function(){
5872         for(var evt in this.events){
5873             if(typeof this.events[evt] == "object"){
5874                  this.events[evt].clearListeners();
5875             }
5876         }
5877     },
5878
5879     relayEvents : function(o, events){
5880         var createHandler = function(ename){
5881             return function(){
5882                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5883             };
5884         };
5885         for(var i = 0, len = events.length; i < len; i++){
5886             var ename = events[i];
5887             if(!this.events[ename]){ this.events[ename] = true; };
5888             o.on(ename, createHandler(ename), this);
5889         }
5890     },
5891
5892     /**
5893      * Used to define events on this Observable
5894      * @param {Object} object The object with the events defined
5895      */
5896     addEvents : function(o){
5897         if(!this.events){
5898             this.events = {};
5899         }
5900         Roo.applyIf(this.events, o);
5901     },
5902
5903     /**
5904      * Checks to see if this object has any listeners for a specified event
5905      * @param {String} eventName The name of the event to check for
5906      * @return {Boolean} True if the event is being listened for, else false
5907      */
5908     hasListener : function(eventName){
5909         var e = this.events[eventName];
5910         return typeof e == "object" && e.listeners.length > 0;
5911     }
5912 };
5913 /**
5914  * Appends an event handler to this element (shorthand for addListener)
5915  * @param {String}   eventName     The type of event to listen for
5916  * @param {Function} handler        The method the event invokes
5917  * @param {Object}   scope (optional) The scope in which to execute the handler
5918  * function. The handler function's "this" context.
5919  * @param {Object}   options  (optional)
5920  * @method
5921  */
5922 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5923 /**
5924  * Removes a listener (shorthand for removeListener)
5925  * @param {String}   eventName     The type of event to listen for
5926  * @param {Function} handler        The handler to remove
5927  * @param {Object}   scope  (optional) The scope (this object) for the handler
5928  * @method
5929  */
5930 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5931
5932 /**
5933  * Starts capture on the specified Observable. All events will be passed
5934  * to the supplied function with the event name + standard signature of the event
5935  * <b>before</b> the event is fired. If the supplied function returns false,
5936  * the event will not fire.
5937  * @param {Observable} o The Observable to capture
5938  * @param {Function} fn The function to call
5939  * @param {Object} scope (optional) The scope (this object) for the fn
5940  * @static
5941  */
5942 Roo.util.Observable.capture = function(o, fn, scope){
5943     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5944 };
5945
5946 /**
5947  * Removes <b>all</b> added captures from the Observable.
5948  * @param {Observable} o The Observable to release
5949  * @static
5950  */
5951 Roo.util.Observable.releaseCapture = function(o){
5952     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5953 };
5954
5955 (function(){
5956
5957     var createBuffered = function(h, o, scope){
5958         var task = new Roo.util.DelayedTask();
5959         return function(){
5960             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5961         };
5962     };
5963
5964     var createSingle = function(h, e, fn, scope){
5965         return function(){
5966             e.removeListener(fn, scope);
5967             return h.apply(scope, arguments);
5968         };
5969     };
5970
5971     var createDelayed = function(h, o, scope){
5972         return function(){
5973             var args = Array.prototype.slice.call(arguments, 0);
5974             setTimeout(function(){
5975                 h.apply(scope, args);
5976             }, o.delay || 10);
5977         };
5978     };
5979
5980     Roo.util.Event = function(obj, name){
5981         this.name = name;
5982         this.obj = obj;
5983         this.listeners = [];
5984     };
5985
5986     Roo.util.Event.prototype = {
5987         addListener : function(fn, scope, options){
5988             var o = options || {};
5989             scope = scope || this.obj;
5990             if(!this.isListening(fn, scope)){
5991                 var l = {fn: fn, scope: scope, options: o};
5992                 var h = fn;
5993                 if(o.delay){
5994                     h = createDelayed(h, o, scope);
5995                 }
5996                 if(o.single){
5997                     h = createSingle(h, this, fn, scope);
5998                 }
5999                 if(o.buffer){
6000                     h = createBuffered(h, o, scope);
6001                 }
6002                 l.fireFn = h;
6003                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6004                     this.listeners.push(l);
6005                 }else{
6006                     this.listeners = this.listeners.slice(0);
6007                     this.listeners.push(l);
6008                 }
6009             }
6010         },
6011
6012         findListener : function(fn, scope){
6013             scope = scope || this.obj;
6014             var ls = this.listeners;
6015             for(var i = 0, len = ls.length; i < len; i++){
6016                 var l = ls[i];
6017                 if(l.fn == fn && l.scope == scope){
6018                     return i;
6019                 }
6020             }
6021             return -1;
6022         },
6023
6024         isListening : function(fn, scope){
6025             return this.findListener(fn, scope) != -1;
6026         },
6027
6028         removeListener : function(fn, scope){
6029             var index;
6030             if((index = this.findListener(fn, scope)) != -1){
6031                 if(!this.firing){
6032                     this.listeners.splice(index, 1);
6033                 }else{
6034                     this.listeners = this.listeners.slice(0);
6035                     this.listeners.splice(index, 1);
6036                 }
6037                 return true;
6038             }
6039             return false;
6040         },
6041
6042         clearListeners : function(){
6043             this.listeners = [];
6044         },
6045
6046         fire : function(){
6047             var ls = this.listeners, scope, len = ls.length;
6048             if(len > 0){
6049                 this.firing = true;
6050                 var args = Array.prototype.slice.call(arguments, 0);
6051                 for(var i = 0; i < len; i++){
6052                     var l = ls[i];
6053                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6054                         this.firing = false;
6055                         return false;
6056                     }
6057                 }
6058                 this.firing = false;
6059             }
6060             return true;
6061         }
6062     };
6063 })();/*
6064  * RooJS Library 
6065  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066  *
6067  * Licence LGPL 
6068  *
6069  */
6070  
6071 /**
6072  * @class Roo.Document
6073  * @extends Roo.util.Observable
6074  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6075  * 
6076  * @param {Object} config the methods and properties of the 'base' class for the application.
6077  * 
6078  *  Generic Page handler - implement this to start your app..
6079  * 
6080  * eg.
6081  *  MyProject = new Roo.Document({
6082         events : {
6083             'load' : true // your events..
6084         },
6085         listeners : {
6086             'ready' : function() {
6087                 // fired on Roo.onReady()
6088             }
6089         }
6090  * 
6091  */
6092 Roo.Document = function(cfg) {
6093      
6094     this.addEvents({ 
6095         'ready' : true
6096     });
6097     Roo.util.Observable.call(this,cfg);
6098     
6099     var _this = this;
6100     
6101     Roo.onReady(function() {
6102         _this.fireEvent('ready');
6103     },null,false);
6104     
6105     
6106 }
6107
6108 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6109  * Based on:
6110  * Ext JS Library 1.1.1
6111  * Copyright(c) 2006-2007, Ext JS, LLC.
6112  *
6113  * Originally Released Under LGPL - original licence link has changed is not relivant.
6114  *
6115  * Fork - LGPL
6116  * <script type="text/javascript">
6117  */
6118
6119 /**
6120  * @class Roo.EventManager
6121  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6122  * several useful events directly.
6123  * See {@link Roo.EventObject} for more details on normalized event objects.
6124  * @singleton
6125  */
6126 Roo.EventManager = function(){
6127     var docReadyEvent, docReadyProcId, docReadyState = false;
6128     var resizeEvent, resizeTask, textEvent, textSize;
6129     var E = Roo.lib.Event;
6130     var D = Roo.lib.Dom;
6131
6132     
6133     
6134
6135     var fireDocReady = function(){
6136         if(!docReadyState){
6137             docReadyState = true;
6138             Roo.isReady = true;
6139             if(docReadyProcId){
6140                 clearInterval(docReadyProcId);
6141             }
6142             if(Roo.isGecko || Roo.isOpera) {
6143                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6144             }
6145             if(Roo.isIE){
6146                 var defer = document.getElementById("ie-deferred-loader");
6147                 if(defer){
6148                     defer.onreadystatechange = null;
6149                     defer.parentNode.removeChild(defer);
6150                 }
6151             }
6152             if(docReadyEvent){
6153                 docReadyEvent.fire();
6154                 docReadyEvent.clearListeners();
6155             }
6156         }
6157     };
6158     
6159     var initDocReady = function(){
6160         docReadyEvent = new Roo.util.Event();
6161         if(Roo.isGecko || Roo.isOpera) {
6162             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6163         }else if(Roo.isIE){
6164             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6165             var defer = document.getElementById("ie-deferred-loader");
6166             defer.onreadystatechange = function(){
6167                 if(this.readyState == "complete"){
6168                     fireDocReady();
6169                 }
6170             };
6171         }else if(Roo.isSafari){ 
6172             docReadyProcId = setInterval(function(){
6173                 var rs = document.readyState;
6174                 if(rs == "complete") {
6175                     fireDocReady();     
6176                  }
6177             }, 10);
6178         }
6179         // no matter what, make sure it fires on load
6180         E.on(window, "load", fireDocReady);
6181     };
6182
6183     var createBuffered = function(h, o){
6184         var task = new Roo.util.DelayedTask(h);
6185         return function(e){
6186             // create new event object impl so new events don't wipe out properties
6187             e = new Roo.EventObjectImpl(e);
6188             task.delay(o.buffer, h, null, [e]);
6189         };
6190     };
6191
6192     var createSingle = function(h, el, ename, fn){
6193         return function(e){
6194             Roo.EventManager.removeListener(el, ename, fn);
6195             h(e);
6196         };
6197     };
6198
6199     var createDelayed = function(h, o){
6200         return function(e){
6201             // create new event object impl so new events don't wipe out properties
6202             e = new Roo.EventObjectImpl(e);
6203             setTimeout(function(){
6204                 h(e);
6205             }, o.delay || 10);
6206         };
6207     };
6208     var transitionEndVal = false;
6209     
6210     var transitionEnd = function()
6211     {
6212         if (transitionEndVal) {
6213             return transitionEndVal;
6214         }
6215         var el = document.createElement('div');
6216
6217         var transEndEventNames = {
6218             WebkitTransition : 'webkitTransitionEnd',
6219             MozTransition    : 'transitionend',
6220             OTransition      : 'oTransitionEnd otransitionend',
6221             transition       : 'transitionend'
6222         };
6223     
6224         for (var name in transEndEventNames) {
6225             if (el.style[name] !== undefined) {
6226                 transitionEndVal = transEndEventNames[name];
6227                 return  transitionEndVal ;
6228             }
6229         }
6230     }
6231     
6232
6233     var listen = function(element, ename, opt, fn, scope){
6234         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6235         fn = fn || o.fn; scope = scope || o.scope;
6236         var el = Roo.getDom(element);
6237         
6238         
6239         if(!el){
6240             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6241         }
6242         
6243         if (ename == 'transitionend') {
6244             ename = transitionEnd();
6245         }
6246         var h = function(e){
6247             e = Roo.EventObject.setEvent(e);
6248             var t;
6249             if(o.delegate){
6250                 t = e.getTarget(o.delegate, el);
6251                 if(!t){
6252                     return;
6253                 }
6254             }else{
6255                 t = e.target;
6256             }
6257             if(o.stopEvent === true){
6258                 e.stopEvent();
6259             }
6260             if(o.preventDefault === true){
6261                e.preventDefault();
6262             }
6263             if(o.stopPropagation === true){
6264                 e.stopPropagation();
6265             }
6266
6267             if(o.normalized === false){
6268                 e = e.browserEvent;
6269             }
6270
6271             fn.call(scope || el, e, t, o);
6272         };
6273         if(o.delay){
6274             h = createDelayed(h, o);
6275         }
6276         if(o.single){
6277             h = createSingle(h, el, ename, fn);
6278         }
6279         if(o.buffer){
6280             h = createBuffered(h, o);
6281         }
6282         
6283         fn._handlers = fn._handlers || [];
6284         
6285         
6286         fn._handlers.push([Roo.id(el), ename, h]);
6287         
6288         
6289          
6290         E.on(el, ename, h);
6291         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6292             el.addEventListener("DOMMouseScroll", h, false);
6293             E.on(window, 'unload', function(){
6294                 el.removeEventListener("DOMMouseScroll", h, false);
6295             });
6296         }
6297         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6298             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6299         }
6300         return h;
6301     };
6302
6303     var stopListening = function(el, ename, fn){
6304         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6305         if(hds){
6306             for(var i = 0, len = hds.length; i < len; i++){
6307                 var h = hds[i];
6308                 if(h[0] == id && h[1] == ename){
6309                     hd = h[2];
6310                     hds.splice(i, 1);
6311                     break;
6312                 }
6313             }
6314         }
6315         E.un(el, ename, hd);
6316         el = Roo.getDom(el);
6317         if(ename == "mousewheel" && el.addEventListener){
6318             el.removeEventListener("DOMMouseScroll", hd, false);
6319         }
6320         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6321             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6322         }
6323     };
6324
6325     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6326     
6327     var pub = {
6328         
6329         
6330         /** 
6331          * Fix for doc tools
6332          * @scope Roo.EventManager
6333          */
6334         
6335         
6336         /** 
6337          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6338          * object with a Roo.EventObject
6339          * @param {Function} fn        The method the event invokes
6340          * @param {Object}   scope    An object that becomes the scope of the handler
6341          * @param {boolean}  override If true, the obj passed in becomes
6342          *                             the execution scope of the listener
6343          * @return {Function} The wrapped function
6344          * @deprecated
6345          */
6346         wrap : function(fn, scope, override){
6347             return function(e){
6348                 Roo.EventObject.setEvent(e);
6349                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6350             };
6351         },
6352         
6353         /**
6354      * Appends an event handler to an element (shorthand for addListener)
6355      * @param {String/HTMLElement}   element        The html element or id to assign the
6356      * @param {String}   eventName The type of event to listen for
6357      * @param {Function} handler The method the event invokes
6358      * @param {Object}   scope (optional) The scope in which to execute the handler
6359      * function. The handler function's "this" context.
6360      * @param {Object}   options (optional) An object containing handler configuration
6361      * properties. This may contain any of the following properties:<ul>
6362      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6363      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6364      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6365      * <li>preventDefault {Boolean} True to prevent the default action</li>
6366      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6367      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6368      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6369      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6370      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6371      * by the specified number of milliseconds. If the event fires again within that time, the original
6372      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6373      * </ul><br>
6374      * <p>
6375      * <b>Combining Options</b><br>
6376      * Using the options argument, it is possible to combine different types of listeners:<br>
6377      * <br>
6378      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6379      * Code:<pre><code>
6380 el.on('click', this.onClick, this, {
6381     single: true,
6382     delay: 100,
6383     stopEvent : true,
6384     forumId: 4
6385 });</code></pre>
6386      * <p>
6387      * <b>Attaching multiple handlers in 1 call</b><br>
6388       * The method also allows for a single argument to be passed which is a config object containing properties
6389      * which specify multiple handlers.
6390      * <p>
6391      * Code:<pre><code>
6392 el.on({
6393     'click' : {
6394         fn: this.onClick
6395         scope: this,
6396         delay: 100
6397     },
6398     'mouseover' : {
6399         fn: this.onMouseOver
6400         scope: this
6401     },
6402     'mouseout' : {
6403         fn: this.onMouseOut
6404         scope: this
6405     }
6406 });</code></pre>
6407      * <p>
6408      * Or a shorthand syntax:<br>
6409      * Code:<pre><code>
6410 el.on({
6411     'click' : this.onClick,
6412     'mouseover' : this.onMouseOver,
6413     'mouseout' : this.onMouseOut
6414     scope: this
6415 });</code></pre>
6416      */
6417         addListener : function(element, eventName, fn, scope, options){
6418             if(typeof eventName == "object"){
6419                 var o = eventName;
6420                 for(var e in o){
6421                     if(propRe.test(e)){
6422                         continue;
6423                     }
6424                     if(typeof o[e] == "function"){
6425                         // shared options
6426                         listen(element, e, o, o[e], o.scope);
6427                     }else{
6428                         // individual options
6429                         listen(element, e, o[e]);
6430                     }
6431                 }
6432                 return;
6433             }
6434             return listen(element, eventName, options, fn, scope);
6435         },
6436         
6437         /**
6438          * Removes an event handler
6439          *
6440          * @param {String/HTMLElement}   element        The id or html element to remove the 
6441          *                             event from
6442          * @param {String}   eventName     The type of event
6443          * @param {Function} fn
6444          * @return {Boolean} True if a listener was actually removed
6445          */
6446         removeListener : function(element, eventName, fn){
6447             return stopListening(element, eventName, fn);
6448         },
6449         
6450         /**
6451          * Fires when the document is ready (before onload and before images are loaded). Can be 
6452          * accessed shorthanded Roo.onReady().
6453          * @param {Function} fn        The method the event invokes
6454          * @param {Object}   scope    An  object that becomes the scope of the handler
6455          * @param {boolean}  options
6456          */
6457         onDocumentReady : function(fn, scope, options){
6458             if(docReadyState){ // if it already fired
6459                 docReadyEvent.addListener(fn, scope, options);
6460                 docReadyEvent.fire();
6461                 docReadyEvent.clearListeners();
6462                 return;
6463             }
6464             if(!docReadyEvent){
6465                 initDocReady();
6466             }
6467             docReadyEvent.addListener(fn, scope, options);
6468         },
6469         
6470         /**
6471          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6472          * @param {Function} fn        The method the event invokes
6473          * @param {Object}   scope    An object that becomes the scope of the handler
6474          * @param {boolean}  options
6475          */
6476         onWindowResize : function(fn, scope, options){
6477             if(!resizeEvent){
6478                 resizeEvent = new Roo.util.Event();
6479                 resizeTask = new Roo.util.DelayedTask(function(){
6480                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6481                 });
6482                 E.on(window, "resize", function(){
6483                     if(Roo.isIE){
6484                         resizeTask.delay(50);
6485                     }else{
6486                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6487                     }
6488                 });
6489             }
6490             resizeEvent.addListener(fn, scope, options);
6491         },
6492
6493         /**
6494          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6495          * @param {Function} fn        The method the event invokes
6496          * @param {Object}   scope    An object that becomes the scope of the handler
6497          * @param {boolean}  options
6498          */
6499         onTextResize : function(fn, scope, options){
6500             if(!textEvent){
6501                 textEvent = new Roo.util.Event();
6502                 var textEl = new Roo.Element(document.createElement('div'));
6503                 textEl.dom.className = 'x-text-resize';
6504                 textEl.dom.innerHTML = 'X';
6505                 textEl.appendTo(document.body);
6506                 textSize = textEl.dom.offsetHeight;
6507                 setInterval(function(){
6508                     if(textEl.dom.offsetHeight != textSize){
6509                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6510                     }
6511                 }, this.textResizeInterval);
6512             }
6513             textEvent.addListener(fn, scope, options);
6514         },
6515
6516         /**
6517          * Removes the passed window resize listener.
6518          * @param {Function} fn        The method the event invokes
6519          * @param {Object}   scope    The scope of handler
6520          */
6521         removeResizeListener : function(fn, scope){
6522             if(resizeEvent){
6523                 resizeEvent.removeListener(fn, scope);
6524             }
6525         },
6526
6527         // private
6528         fireResize : function(){
6529             if(resizeEvent){
6530                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6531             }   
6532         },
6533         /**
6534          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6535          */
6536         ieDeferSrc : false,
6537         /**
6538          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6539          */
6540         textResizeInterval : 50
6541     };
6542     
6543     /**
6544      * Fix for doc tools
6545      * @scopeAlias pub=Roo.EventManager
6546      */
6547     
6548      /**
6549      * Appends an event handler to an element (shorthand for addListener)
6550      * @param {String/HTMLElement}   element        The html element or id to assign the
6551      * @param {String}   eventName The type of event to listen for
6552      * @param {Function} handler The method the event invokes
6553      * @param {Object}   scope (optional) The scope in which to execute the handler
6554      * function. The handler function's "this" context.
6555      * @param {Object}   options (optional) An object containing handler configuration
6556      * properties. This may contain any of the following properties:<ul>
6557      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6558      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6559      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6560      * <li>preventDefault {Boolean} True to prevent the default action</li>
6561      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6562      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6563      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6564      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6565      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6566      * by the specified number of milliseconds. If the event fires again within that time, the original
6567      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6568      * </ul><br>
6569      * <p>
6570      * <b>Combining Options</b><br>
6571      * Using the options argument, it is possible to combine different types of listeners:<br>
6572      * <br>
6573      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6574      * Code:<pre><code>
6575 el.on('click', this.onClick, this, {
6576     single: true,
6577     delay: 100,
6578     stopEvent : true,
6579     forumId: 4
6580 });</code></pre>
6581      * <p>
6582      * <b>Attaching multiple handlers in 1 call</b><br>
6583       * The method also allows for a single argument to be passed which is a config object containing properties
6584      * which specify multiple handlers.
6585      * <p>
6586      * Code:<pre><code>
6587 el.on({
6588     'click' : {
6589         fn: this.onClick
6590         scope: this,
6591         delay: 100
6592     },
6593     'mouseover' : {
6594         fn: this.onMouseOver
6595         scope: this
6596     },
6597     'mouseout' : {
6598         fn: this.onMouseOut
6599         scope: this
6600     }
6601 });</code></pre>
6602      * <p>
6603      * Or a shorthand syntax:<br>
6604      * Code:<pre><code>
6605 el.on({
6606     'click' : this.onClick,
6607     'mouseover' : this.onMouseOver,
6608     'mouseout' : this.onMouseOut
6609     scope: this
6610 });</code></pre>
6611      */
6612     pub.on = pub.addListener;
6613     pub.un = pub.removeListener;
6614
6615     pub.stoppedMouseDownEvent = new Roo.util.Event();
6616     return pub;
6617 }();
6618 /**
6619   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6620   * @param {Function} fn        The method the event invokes
6621   * @param {Object}   scope    An  object that becomes the scope of the handler
6622   * @param {boolean}  override If true, the obj passed in becomes
6623   *                             the execution scope of the listener
6624   * @member Roo
6625   * @method onReady
6626  */
6627 Roo.onReady = Roo.EventManager.onDocumentReady;
6628
6629 Roo.onReady(function(){
6630     var bd = Roo.get(document.body);
6631     if(!bd){ return; }
6632
6633     var cls = [
6634             Roo.isIE ? "roo-ie"
6635             : Roo.isIE11 ? "roo-ie11"
6636             : Roo.isEdge ? "roo-edge"
6637             : Roo.isGecko ? "roo-gecko"
6638             : Roo.isOpera ? "roo-opera"
6639             : Roo.isSafari ? "roo-safari" : ""];
6640
6641     if(Roo.isMac){
6642         cls.push("roo-mac");
6643     }
6644     if(Roo.isLinux){
6645         cls.push("roo-linux");
6646     }
6647     if(Roo.isIOS){
6648         cls.push("roo-ios");
6649     }
6650     if(Roo.isTouch){
6651         cls.push("roo-touch");
6652     }
6653     if(Roo.isBorderBox){
6654         cls.push('roo-border-box');
6655     }
6656     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6657         var p = bd.dom.parentNode;
6658         if(p){
6659             p.className += ' roo-strict';
6660         }
6661     }
6662     bd.addClass(cls.join(' '));
6663 });
6664
6665 /**
6666  * @class Roo.EventObject
6667  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6668  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6669  * Example:
6670  * <pre><code>
6671  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6672     e.preventDefault();
6673     var target = e.getTarget();
6674     ...
6675  }
6676  var myDiv = Roo.get("myDiv");
6677  myDiv.on("click", handleClick);
6678  //or
6679  Roo.EventManager.on("myDiv", 'click', handleClick);
6680  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6681  </code></pre>
6682  * @singleton
6683  */
6684 Roo.EventObject = function(){
6685     
6686     var E = Roo.lib.Event;
6687     
6688     // safari keypress events for special keys return bad keycodes
6689     var safariKeys = {
6690         63234 : 37, // left
6691         63235 : 39, // right
6692         63232 : 38, // up
6693         63233 : 40, // down
6694         63276 : 33, // page up
6695         63277 : 34, // page down
6696         63272 : 46, // delete
6697         63273 : 36, // home
6698         63275 : 35  // end
6699     };
6700
6701     // normalize button clicks
6702     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6703                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6704
6705     Roo.EventObjectImpl = function(e){
6706         if(e){
6707             this.setEvent(e.browserEvent || e);
6708         }
6709     };
6710     Roo.EventObjectImpl.prototype = {
6711         /**
6712          * Used to fix doc tools.
6713          * @scope Roo.EventObject.prototype
6714          */
6715             
6716
6717         
6718         
6719         /** The normal browser event */
6720         browserEvent : null,
6721         /** The button pressed in a mouse event */
6722         button : -1,
6723         /** True if the shift key was down during the event */
6724         shiftKey : false,
6725         /** True if the control key was down during the event */
6726         ctrlKey : false,
6727         /** True if the alt key was down during the event */
6728         altKey : false,
6729
6730         /** Key constant 
6731         * @type Number */
6732         BACKSPACE : 8,
6733         /** Key constant 
6734         * @type Number */
6735         TAB : 9,
6736         /** Key constant 
6737         * @type Number */
6738         RETURN : 13,
6739         /** Key constant 
6740         * @type Number */
6741         ENTER : 13,
6742         /** Key constant 
6743         * @type Number */
6744         SHIFT : 16,
6745         /** Key constant 
6746         * @type Number */
6747         CONTROL : 17,
6748         /** Key constant 
6749         * @type Number */
6750         ESC : 27,
6751         /** Key constant 
6752         * @type Number */
6753         SPACE : 32,
6754         /** Key constant 
6755         * @type Number */
6756         PAGEUP : 33,
6757         /** Key constant 
6758         * @type Number */
6759         PAGEDOWN : 34,
6760         /** Key constant 
6761         * @type Number */
6762         END : 35,
6763         /** Key constant 
6764         * @type Number */
6765         HOME : 36,
6766         /** Key constant 
6767         * @type Number */
6768         LEFT : 37,
6769         /** Key constant 
6770         * @type Number */
6771         UP : 38,
6772         /** Key constant 
6773         * @type Number */
6774         RIGHT : 39,
6775         /** Key constant 
6776         * @type Number */
6777         DOWN : 40,
6778         /** Key constant 
6779         * @type Number */
6780         DELETE : 46,
6781         /** Key constant 
6782         * @type Number */
6783         F5 : 116,
6784
6785            /** @private */
6786         setEvent : function(e){
6787             if(e == this || (e && e.browserEvent)){ // already wrapped
6788                 return e;
6789             }
6790             this.browserEvent = e;
6791             if(e){
6792                 // normalize buttons
6793                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6794                 if(e.type == 'click' && this.button == -1){
6795                     this.button = 0;
6796                 }
6797                 this.type = e.type;
6798                 this.shiftKey = e.shiftKey;
6799                 // mac metaKey behaves like ctrlKey
6800                 this.ctrlKey = e.ctrlKey || e.metaKey;
6801                 this.altKey = e.altKey;
6802                 // in getKey these will be normalized for the mac
6803                 this.keyCode = e.keyCode;
6804                 // keyup warnings on firefox.
6805                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6806                 // cache the target for the delayed and or buffered events
6807                 this.target = E.getTarget(e);
6808                 // same for XY
6809                 this.xy = E.getXY(e);
6810             }else{
6811                 this.button = -1;
6812                 this.shiftKey = false;
6813                 this.ctrlKey = false;
6814                 this.altKey = false;
6815                 this.keyCode = 0;
6816                 this.charCode =0;
6817                 this.target = null;
6818                 this.xy = [0, 0];
6819             }
6820             return this;
6821         },
6822
6823         /**
6824          * Stop the event (preventDefault and stopPropagation)
6825          */
6826         stopEvent : function(){
6827             if(this.browserEvent){
6828                 if(this.browserEvent.type == 'mousedown'){
6829                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6830                 }
6831                 E.stopEvent(this.browserEvent);
6832             }
6833         },
6834
6835         /**
6836          * Prevents the browsers default handling of the event.
6837          */
6838         preventDefault : function(){
6839             if(this.browserEvent){
6840                 E.preventDefault(this.browserEvent);
6841             }
6842         },
6843
6844         /** @private */
6845         isNavKeyPress : function(){
6846             var k = this.keyCode;
6847             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6848             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6849         },
6850
6851         isSpecialKey : function(){
6852             var k = this.keyCode;
6853             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6854             (k == 16) || (k == 17) ||
6855             (k >= 18 && k <= 20) ||
6856             (k >= 33 && k <= 35) ||
6857             (k >= 36 && k <= 39) ||
6858             (k >= 44 && k <= 45);
6859         },
6860         /**
6861          * Cancels bubbling of the event.
6862          */
6863         stopPropagation : function(){
6864             if(this.browserEvent){
6865                 if(this.type == 'mousedown'){
6866                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6867                 }
6868                 E.stopPropagation(this.browserEvent);
6869             }
6870         },
6871
6872         /**
6873          * Gets the key code for the event.
6874          * @return {Number}
6875          */
6876         getCharCode : function(){
6877             return this.charCode || this.keyCode;
6878         },
6879
6880         /**
6881          * Returns a normalized keyCode for the event.
6882          * @return {Number} The key code
6883          */
6884         getKey : function(){
6885             var k = this.keyCode || this.charCode;
6886             return Roo.isSafari ? (safariKeys[k] || k) : k;
6887         },
6888
6889         /**
6890          * Gets the x coordinate of the event.
6891          * @return {Number}
6892          */
6893         getPageX : function(){
6894             return this.xy[0];
6895         },
6896
6897         /**
6898          * Gets the y coordinate of the event.
6899          * @return {Number}
6900          */
6901         getPageY : function(){
6902             return this.xy[1];
6903         },
6904
6905         /**
6906          * Gets the time of the event.
6907          * @return {Number}
6908          */
6909         getTime : function(){
6910             if(this.browserEvent){
6911                 return E.getTime(this.browserEvent);
6912             }
6913             return null;
6914         },
6915
6916         /**
6917          * Gets the page coordinates of the event.
6918          * @return {Array} The xy values like [x, y]
6919          */
6920         getXY : function(){
6921             return this.xy;
6922         },
6923
6924         /**
6925          * Gets the target for the event.
6926          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6927          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6928                 search as a number or element (defaults to 10 || document.body)
6929          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6930          * @return {HTMLelement}
6931          */
6932         getTarget : function(selector, maxDepth, returnEl){
6933             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6934         },
6935         /**
6936          * Gets the related target.
6937          * @return {HTMLElement}
6938          */
6939         getRelatedTarget : function(){
6940             if(this.browserEvent){
6941                 return E.getRelatedTarget(this.browserEvent);
6942             }
6943             return null;
6944         },
6945
6946         /**
6947          * Normalizes mouse wheel delta across browsers
6948          * @return {Number} The delta
6949          */
6950         getWheelDelta : function(){
6951             var e = this.browserEvent;
6952             var delta = 0;
6953             if(e.wheelDelta){ /* IE/Opera. */
6954                 delta = e.wheelDelta/120;
6955             }else if(e.detail){ /* Mozilla case. */
6956                 delta = -e.detail/3;
6957             }
6958             return delta;
6959         },
6960
6961         /**
6962          * Returns true if the control, meta, shift or alt key was pressed during this event.
6963          * @return {Boolean}
6964          */
6965         hasModifier : function(){
6966             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6967         },
6968
6969         /**
6970          * Returns true if the target of this event equals el or is a child of el
6971          * @param {String/HTMLElement/Element} el
6972          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6973          * @return {Boolean}
6974          */
6975         within : function(el, related){
6976             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6977             return t && Roo.fly(el).contains(t);
6978         },
6979
6980         getPoint : function(){
6981             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6982         }
6983     };
6984
6985     return new Roo.EventObjectImpl();
6986 }();
6987             
6988     /*
6989  * Based on:
6990  * Ext JS Library 1.1.1
6991  * Copyright(c) 2006-2007, Ext JS, LLC.
6992  *
6993  * Originally Released Under LGPL - original licence link has changed is not relivant.
6994  *
6995  * Fork - LGPL
6996  * <script type="text/javascript">
6997  */
6998
6999  
7000 // was in Composite Element!??!?!
7001  
7002 (function(){
7003     var D = Roo.lib.Dom;
7004     var E = Roo.lib.Event;
7005     var A = Roo.lib.Anim;
7006
7007     // local style camelizing for speed
7008     var propCache = {};
7009     var camelRe = /(-[a-z])/gi;
7010     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7011     var view = document.defaultView;
7012
7013 /**
7014  * @class Roo.Element
7015  * Represents an Element in the DOM.<br><br>
7016  * Usage:<br>
7017 <pre><code>
7018 var el = Roo.get("my-div");
7019
7020 // or with getEl
7021 var el = getEl("my-div");
7022
7023 // or with a DOM element
7024 var el = Roo.get(myDivElement);
7025 </code></pre>
7026  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7027  * each call instead of constructing a new one.<br><br>
7028  * <b>Animations</b><br />
7029  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7030  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7031 <pre>
7032 Option    Default   Description
7033 --------- --------  ---------------------------------------------
7034 duration  .35       The duration of the animation in seconds
7035 easing    easeOut   The YUI easing method
7036 callback  none      A function to execute when the anim completes
7037 scope     this      The scope (this) of the callback function
7038 </pre>
7039 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7040 * manipulate the animation. Here's an example:
7041 <pre><code>
7042 var el = Roo.get("my-div");
7043
7044 // no animation
7045 el.setWidth(100);
7046
7047 // default animation
7048 el.setWidth(100, true);
7049
7050 // animation with some options set
7051 el.setWidth(100, {
7052     duration: 1,
7053     callback: this.foo,
7054     scope: this
7055 });
7056
7057 // using the "anim" property to get the Anim object
7058 var opt = {
7059     duration: 1,
7060     callback: this.foo,
7061     scope: this
7062 };
7063 el.setWidth(100, opt);
7064 ...
7065 if(opt.anim.isAnimated()){
7066     opt.anim.stop();
7067 }
7068 </code></pre>
7069 * <b> Composite (Collections of) Elements</b><br />
7070  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7071  * @constructor Create a new Element directly.
7072  * @param {String/HTMLElement} element
7073  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7074  */
7075     Roo.Element = function(element, forceNew){
7076         var dom = typeof element == "string" ?
7077                 document.getElementById(element) : element;
7078         if(!dom){ // invalid id/element
7079             return null;
7080         }
7081         var id = dom.id;
7082         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7083             return Roo.Element.cache[id];
7084         }
7085
7086         /**
7087          * The DOM element
7088          * @type HTMLElement
7089          */
7090         this.dom = dom;
7091
7092         /**
7093          * The DOM element ID
7094          * @type String
7095          */
7096         this.id = id || Roo.id(dom);
7097     };
7098
7099     var El = Roo.Element;
7100
7101     El.prototype = {
7102         /**
7103          * The element's default display mode  (defaults to "")
7104          * @type String
7105          */
7106         originalDisplay : "",
7107
7108         visibilityMode : 1,
7109         /**
7110          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7111          * @type String
7112          */
7113         defaultUnit : "px",
7114         
7115         /**
7116          * Sets the element's visibility mode. When setVisible() is called it
7117          * will use this to determine whether to set the visibility or the display property.
7118          * @param visMode Element.VISIBILITY or Element.DISPLAY
7119          * @return {Roo.Element} this
7120          */
7121         setVisibilityMode : function(visMode){
7122             this.visibilityMode = visMode;
7123             return this;
7124         },
7125         /**
7126          * Convenience method for setVisibilityMode(Element.DISPLAY)
7127          * @param {String} display (optional) What to set display to when visible
7128          * @return {Roo.Element} this
7129          */
7130         enableDisplayMode : function(display){
7131             this.setVisibilityMode(El.DISPLAY);
7132             if(typeof display != "undefined") { this.originalDisplay = display; }
7133             return this;
7134         },
7135
7136         /**
7137          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7138          * @param {String} selector The simple selector to test
7139          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7140                 search as a number or element (defaults to 10 || document.body)
7141          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7142          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7143          */
7144         findParent : function(simpleSelector, maxDepth, returnEl){
7145             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7146             maxDepth = maxDepth || 50;
7147             if(typeof maxDepth != "number"){
7148                 stopEl = Roo.getDom(maxDepth);
7149                 maxDepth = 10;
7150             }
7151             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7152                 if(dq.is(p, simpleSelector)){
7153                     return returnEl ? Roo.get(p) : p;
7154                 }
7155                 depth++;
7156                 p = p.parentNode;
7157             }
7158             return null;
7159         },
7160
7161
7162         /**
7163          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7164          * @param {String} selector The simple selector to test
7165          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7166                 search as a number or element (defaults to 10 || document.body)
7167          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7168          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7169          */
7170         findParentNode : function(simpleSelector, maxDepth, returnEl){
7171             var p = Roo.fly(this.dom.parentNode, '_internal');
7172             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7173         },
7174         
7175         /**
7176          * Looks at  the scrollable parent element
7177          */
7178         findScrollableParent : function()
7179         {
7180             var overflowRegex = /(auto|scroll)/;
7181             
7182             if(this.getStyle('position') === 'fixed'){
7183                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7184             }
7185             
7186             var excludeStaticParent = this.getStyle('position') === "absolute";
7187             
7188             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7189                 
7190                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7191                     continue;
7192                 }
7193                 
7194                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7195                     return parent;
7196                 }
7197                 
7198                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7199                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7200                 }
7201             }
7202             
7203             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7204         },
7205
7206         /**
7207          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7208          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7209          * @param {String} selector The simple selector to test
7210          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7211                 search as a number or element (defaults to 10 || document.body)
7212          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7213          */
7214         up : function(simpleSelector, maxDepth){
7215             return this.findParentNode(simpleSelector, maxDepth, true);
7216         },
7217
7218
7219
7220         /**
7221          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7222          * @param {String} selector The simple selector to test
7223          * @return {Boolean} True if this element matches the selector, else false
7224          */
7225         is : function(simpleSelector){
7226             return Roo.DomQuery.is(this.dom, simpleSelector);
7227         },
7228
7229         /**
7230          * Perform animation on this element.
7231          * @param {Object} args The YUI animation control args
7232          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7233          * @param {Function} onComplete (optional) Function to call when animation completes
7234          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7235          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7236          * @return {Roo.Element} this
7237          */
7238         animate : function(args, duration, onComplete, easing, animType){
7239             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7240             return this;
7241         },
7242
7243         /*
7244          * @private Internal animation call
7245          */
7246         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7247             animType = animType || 'run';
7248             opt = opt || {};
7249             var anim = Roo.lib.Anim[animType](
7250                 this.dom, args,
7251                 (opt.duration || defaultDur) || .35,
7252                 (opt.easing || defaultEase) || 'easeOut',
7253                 function(){
7254                     Roo.callback(cb, this);
7255                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7256                 },
7257                 this
7258             );
7259             opt.anim = anim;
7260             return anim;
7261         },
7262
7263         // private legacy anim prep
7264         preanim : function(a, i){
7265             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7266         },
7267
7268         /**
7269          * Removes worthless text nodes
7270          * @param {Boolean} forceReclean (optional) By default the element
7271          * keeps track if it has been cleaned already so
7272          * you can call this over and over. However, if you update the element and
7273          * need to force a reclean, you can pass true.
7274          */
7275         clean : function(forceReclean){
7276             if(this.isCleaned && forceReclean !== true){
7277                 return this;
7278             }
7279             var ns = /\S/;
7280             var d = this.dom, n = d.firstChild, ni = -1;
7281             while(n){
7282                 var nx = n.nextSibling;
7283                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7284                     d.removeChild(n);
7285                 }else{
7286                     n.nodeIndex = ++ni;
7287                 }
7288                 n = nx;
7289             }
7290             this.isCleaned = true;
7291             return this;
7292         },
7293
7294         // private
7295         calcOffsetsTo : function(el){
7296             el = Roo.get(el);
7297             var d = el.dom;
7298             var restorePos = false;
7299             if(el.getStyle('position') == 'static'){
7300                 el.position('relative');
7301                 restorePos = true;
7302             }
7303             var x = 0, y =0;
7304             var op = this.dom;
7305             while(op && op != d && op.tagName != 'HTML'){
7306                 x+= op.offsetLeft;
7307                 y+= op.offsetTop;
7308                 op = op.offsetParent;
7309             }
7310             if(restorePos){
7311                 el.position('static');
7312             }
7313             return [x, y];
7314         },
7315
7316         /**
7317          * Scrolls this element into view within the passed container.
7318          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7319          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7320          * @return {Roo.Element} this
7321          */
7322         scrollIntoView : function(container, hscroll){
7323             var c = Roo.getDom(container) || document.body;
7324             var el = this.dom;
7325
7326             var o = this.calcOffsetsTo(c),
7327                 l = o[0],
7328                 t = o[1],
7329                 b = t+el.offsetHeight,
7330                 r = l+el.offsetWidth;
7331
7332             var ch = c.clientHeight;
7333             var ct = parseInt(c.scrollTop, 10);
7334             var cl = parseInt(c.scrollLeft, 10);
7335             var cb = ct + ch;
7336             var cr = cl + c.clientWidth;
7337
7338             if(t < ct){
7339                 c.scrollTop = t;
7340             }else if(b > cb){
7341                 c.scrollTop = b-ch;
7342             }
7343
7344             if(hscroll !== false){
7345                 if(l < cl){
7346                     c.scrollLeft = l;
7347                 }else if(r > cr){
7348                     c.scrollLeft = r-c.clientWidth;
7349                 }
7350             }
7351             return this;
7352         },
7353
7354         // private
7355         scrollChildIntoView : function(child, hscroll){
7356             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7357         },
7358
7359         /**
7360          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7361          * the new height may not be available immediately.
7362          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7363          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7364          * @param {Function} onComplete (optional) Function to call when animation completes
7365          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7366          * @return {Roo.Element} this
7367          */
7368         autoHeight : function(animate, duration, onComplete, easing){
7369             var oldHeight = this.getHeight();
7370             this.clip();
7371             this.setHeight(1); // force clipping
7372             setTimeout(function(){
7373                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7374                 if(!animate){
7375                     this.setHeight(height);
7376                     this.unclip();
7377                     if(typeof onComplete == "function"){
7378                         onComplete();
7379                     }
7380                 }else{
7381                     this.setHeight(oldHeight); // restore original height
7382                     this.setHeight(height, animate, duration, function(){
7383                         this.unclip();
7384                         if(typeof onComplete == "function") { onComplete(); }
7385                     }.createDelegate(this), easing);
7386                 }
7387             }.createDelegate(this), 0);
7388             return this;
7389         },
7390
7391         /**
7392          * Returns true if this element is an ancestor of the passed element
7393          * @param {HTMLElement/String} el The element to check
7394          * @return {Boolean} True if this element is an ancestor of el, else false
7395          */
7396         contains : function(el){
7397             if(!el){return false;}
7398             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7399         },
7400
7401         /**
7402          * Checks whether the element is currently visible using both visibility and display properties.
7403          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7404          * @return {Boolean} True if the element is currently visible, else false
7405          */
7406         isVisible : function(deep) {
7407             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7408             if(deep !== true || !vis){
7409                 return vis;
7410             }
7411             var p = this.dom.parentNode;
7412             while(p && p.tagName.toLowerCase() != "body"){
7413                 if(!Roo.fly(p, '_isVisible').isVisible()){
7414                     return false;
7415                 }
7416                 p = p.parentNode;
7417             }
7418             return true;
7419         },
7420
7421         /**
7422          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7423          * @param {String} selector The CSS selector
7424          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7425          * @return {CompositeElement/CompositeElementLite} The composite element
7426          */
7427         select : function(selector, unique){
7428             return El.select(selector, unique, this.dom);
7429         },
7430
7431         /**
7432          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7433          * @param {String} selector The CSS selector
7434          * @return {Array} An array of the matched nodes
7435          */
7436         query : function(selector, unique){
7437             return Roo.DomQuery.select(selector, this.dom);
7438         },
7439
7440         /**
7441          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7442          * @param {String} selector The CSS selector
7443          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7444          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7445          */
7446         child : function(selector, returnDom){
7447             var n = Roo.DomQuery.selectNode(selector, this.dom);
7448             return returnDom ? n : Roo.get(n);
7449         },
7450
7451         /**
7452          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7453          * @param {String} selector The CSS selector
7454          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7455          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7456          */
7457         down : function(selector, returnDom){
7458             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7459             return returnDom ? n : Roo.get(n);
7460         },
7461
7462         /**
7463          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7464          * @param {String} group The group the DD object is member of
7465          * @param {Object} config The DD config object
7466          * @param {Object} overrides An object containing methods to override/implement on the DD object
7467          * @return {Roo.dd.DD} The DD object
7468          */
7469         initDD : function(group, config, overrides){
7470             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7471             return Roo.apply(dd, overrides);
7472         },
7473
7474         /**
7475          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7476          * @param {String} group The group the DDProxy object is member of
7477          * @param {Object} config The DDProxy config object
7478          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7479          * @return {Roo.dd.DDProxy} The DDProxy object
7480          */
7481         initDDProxy : function(group, config, overrides){
7482             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7483             return Roo.apply(dd, overrides);
7484         },
7485
7486         /**
7487          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7488          * @param {String} group The group the DDTarget object is member of
7489          * @param {Object} config The DDTarget config object
7490          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7491          * @return {Roo.dd.DDTarget} The DDTarget object
7492          */
7493         initDDTarget : function(group, config, overrides){
7494             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7495             return Roo.apply(dd, overrides);
7496         },
7497
7498         /**
7499          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7500          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7501          * @param {Boolean} visible Whether the element is visible
7502          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7503          * @return {Roo.Element} this
7504          */
7505          setVisible : function(visible, animate){
7506             if(!animate || !A){
7507                 if(this.visibilityMode == El.DISPLAY){
7508                     this.setDisplayed(visible);
7509                 }else{
7510                     this.fixDisplay();
7511                     this.dom.style.visibility = visible ? "visible" : "hidden";
7512                 }
7513             }else{
7514                 // closure for composites
7515                 var dom = this.dom;
7516                 var visMode = this.visibilityMode;
7517                 if(visible){
7518                     this.setOpacity(.01);
7519                     this.setVisible(true);
7520                 }
7521                 this.anim({opacity: { to: (visible?1:0) }},
7522                       this.preanim(arguments, 1),
7523                       null, .35, 'easeIn', function(){
7524                          if(!visible){
7525                              if(visMode == El.DISPLAY){
7526                                  dom.style.display = "none";
7527                              }else{
7528                                  dom.style.visibility = "hidden";
7529                              }
7530                              Roo.get(dom).setOpacity(1);
7531                          }
7532                      });
7533             }
7534             return this;
7535         },
7536
7537         /**
7538          * Returns true if display is not "none"
7539          * @return {Boolean}
7540          */
7541         isDisplayed : function() {
7542             return this.getStyle("display") != "none";
7543         },
7544
7545         /**
7546          * Toggles the element's visibility or display, depending on visibility mode.
7547          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7548          * @return {Roo.Element} this
7549          */
7550         toggle : function(animate){
7551             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7552             return this;
7553         },
7554
7555         /**
7556          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7557          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7558          * @return {Roo.Element} this
7559          */
7560         setDisplayed : function(value) {
7561             if(typeof value == "boolean"){
7562                value = value ? this.originalDisplay : "none";
7563             }
7564             this.setStyle("display", value);
7565             return this;
7566         },
7567
7568         /**
7569          * Tries to focus the element. Any exceptions are caught and ignored.
7570          * @return {Roo.Element} this
7571          */
7572         focus : function() {
7573             try{
7574                 this.dom.focus();
7575             }catch(e){}
7576             return this;
7577         },
7578
7579         /**
7580          * Tries to blur the element. Any exceptions are caught and ignored.
7581          * @return {Roo.Element} this
7582          */
7583         blur : function() {
7584             try{
7585                 this.dom.blur();
7586             }catch(e){}
7587             return this;
7588         },
7589
7590         /**
7591          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7592          * @param {String/Array} className The CSS class to add, or an array of classes
7593          * @return {Roo.Element} this
7594          */
7595         addClass : function(className){
7596             if(className instanceof Array){
7597                 for(var i = 0, len = className.length; i < len; i++) {
7598                     this.addClass(className[i]);
7599                 }
7600             }else{
7601                 if(className && !this.hasClass(className)){
7602                     this.dom.className = this.dom.className + " " + className;
7603                 }
7604             }
7605             return this;
7606         },
7607
7608         /**
7609          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7610          * @param {String/Array} className The CSS class to add, or an array of classes
7611          * @return {Roo.Element} this
7612          */
7613         radioClass : function(className){
7614             var siblings = this.dom.parentNode.childNodes;
7615             for(var i = 0; i < siblings.length; i++) {
7616                 var s = siblings[i];
7617                 if(s.nodeType == 1){
7618                     Roo.get(s).removeClass(className);
7619                 }
7620             }
7621             this.addClass(className);
7622             return this;
7623         },
7624
7625         /**
7626          * Removes one or more CSS classes from the element.
7627          * @param {String/Array} className The CSS class to remove, or an array of classes
7628          * @return {Roo.Element} this
7629          */
7630         removeClass : function(className){
7631             if(!className || !this.dom.className){
7632                 return this;
7633             }
7634             if(className instanceof Array){
7635                 for(var i = 0, len = className.length; i < len; i++) {
7636                     this.removeClass(className[i]);
7637                 }
7638             }else{
7639                 if(this.hasClass(className)){
7640                     var re = this.classReCache[className];
7641                     if (!re) {
7642                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7643                        this.classReCache[className] = re;
7644                     }
7645                     this.dom.className =
7646                         this.dom.className.replace(re, " ");
7647                 }
7648             }
7649             return this;
7650         },
7651
7652         // private
7653         classReCache: {},
7654
7655         /**
7656          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7657          * @param {String} className The CSS class to toggle
7658          * @return {Roo.Element} this
7659          */
7660         toggleClass : function(className){
7661             if(this.hasClass(className)){
7662                 this.removeClass(className);
7663             }else{
7664                 this.addClass(className);
7665             }
7666             return this;
7667         },
7668
7669         /**
7670          * Checks if the specified CSS class exists on this element's DOM node.
7671          * @param {String} className The CSS class to check for
7672          * @return {Boolean} True if the class exists, else false
7673          */
7674         hasClass : function(className){
7675             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7676         },
7677
7678         /**
7679          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7680          * @param {String} oldClassName The CSS class to replace
7681          * @param {String} newClassName The replacement CSS class
7682          * @return {Roo.Element} this
7683          */
7684         replaceClass : function(oldClassName, newClassName){
7685             this.removeClass(oldClassName);
7686             this.addClass(newClassName);
7687             return this;
7688         },
7689
7690         /**
7691          * Returns an object with properties matching the styles requested.
7692          * For example, el.getStyles('color', 'font-size', 'width') might return
7693          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7694          * @param {String} style1 A style name
7695          * @param {String} style2 A style name
7696          * @param {String} etc.
7697          * @return {Object} The style object
7698          */
7699         getStyles : function(){
7700             var a = arguments, len = a.length, r = {};
7701             for(var i = 0; i < len; i++){
7702                 r[a[i]] = this.getStyle(a[i]);
7703             }
7704             return r;
7705         },
7706
7707         /**
7708          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7709          * @param {String} property The style property whose value is returned.
7710          * @return {String} The current value of the style property for this element.
7711          */
7712         getStyle : function(){
7713             return view && view.getComputedStyle ?
7714                 function(prop){
7715                     var el = this.dom, v, cs, camel;
7716                     if(prop == 'float'){
7717                         prop = "cssFloat";
7718                     }
7719                     if(el.style && (v = el.style[prop])){
7720                         return v;
7721                     }
7722                     if(cs = view.getComputedStyle(el, "")){
7723                         if(!(camel = propCache[prop])){
7724                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7725                         }
7726                         return cs[camel];
7727                     }
7728                     return null;
7729                 } :
7730                 function(prop){
7731                     var el = this.dom, v, cs, camel;
7732                     if(prop == 'opacity'){
7733                         if(typeof el.style.filter == 'string'){
7734                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7735                             if(m){
7736                                 var fv = parseFloat(m[1]);
7737                                 if(!isNaN(fv)){
7738                                     return fv ? fv / 100 : 0;
7739                                 }
7740                             }
7741                         }
7742                         return 1;
7743                     }else if(prop == 'float'){
7744                         prop = "styleFloat";
7745                     }
7746                     if(!(camel = propCache[prop])){
7747                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7748                     }
7749                     if(v = el.style[camel]){
7750                         return v;
7751                     }
7752                     if(cs = el.currentStyle){
7753                         return cs[camel];
7754                     }
7755                     return null;
7756                 };
7757         }(),
7758
7759         /**
7760          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7761          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7762          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7763          * @return {Roo.Element} this
7764          */
7765         setStyle : function(prop, value){
7766             if(typeof prop == "string"){
7767                 
7768                 if (prop == 'float') {
7769                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7770                     return this;
7771                 }
7772                 
7773                 var camel;
7774                 if(!(camel = propCache[prop])){
7775                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7776                 }
7777                 
7778                 if(camel == 'opacity') {
7779                     this.setOpacity(value);
7780                 }else{
7781                     this.dom.style[camel] = value;
7782                 }
7783             }else{
7784                 for(var style in prop){
7785                     if(typeof prop[style] != "function"){
7786                        this.setStyle(style, prop[style]);
7787                     }
7788                 }
7789             }
7790             return this;
7791         },
7792
7793         /**
7794          * More flexible version of {@link #setStyle} for setting style properties.
7795          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7796          * a function which returns such a specification.
7797          * @return {Roo.Element} this
7798          */
7799         applyStyles : function(style){
7800             Roo.DomHelper.applyStyles(this.dom, style);
7801             return this;
7802         },
7803
7804         /**
7805           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7806           * @return {Number} The X position of the element
7807           */
7808         getX : function(){
7809             return D.getX(this.dom);
7810         },
7811
7812         /**
7813           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7814           * @return {Number} The Y position of the element
7815           */
7816         getY : function(){
7817             return D.getY(this.dom);
7818         },
7819
7820         /**
7821           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7822           * @return {Array} The XY position of the element
7823           */
7824         getXY : function(){
7825             return D.getXY(this.dom);
7826         },
7827
7828         /**
7829          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7830          * @param {Number} The X position of the element
7831          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7832          * @return {Roo.Element} this
7833          */
7834         setX : function(x, animate){
7835             if(!animate || !A){
7836                 D.setX(this.dom, x);
7837             }else{
7838                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7839             }
7840             return this;
7841         },
7842
7843         /**
7844          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7845          * @param {Number} The Y position of the element
7846          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7847          * @return {Roo.Element} this
7848          */
7849         setY : function(y, animate){
7850             if(!animate || !A){
7851                 D.setY(this.dom, y);
7852             }else{
7853                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7854             }
7855             return this;
7856         },
7857
7858         /**
7859          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7860          * @param {String} left The left CSS property value
7861          * @return {Roo.Element} this
7862          */
7863         setLeft : function(left){
7864             this.setStyle("left", this.addUnits(left));
7865             return this;
7866         },
7867
7868         /**
7869          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7870          * @param {String} top The top CSS property value
7871          * @return {Roo.Element} this
7872          */
7873         setTop : function(top){
7874             this.setStyle("top", this.addUnits(top));
7875             return this;
7876         },
7877
7878         /**
7879          * Sets the element's CSS right style.
7880          * @param {String} right The right CSS property value
7881          * @return {Roo.Element} this
7882          */
7883         setRight : function(right){
7884             this.setStyle("right", this.addUnits(right));
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the element's CSS bottom style.
7890          * @param {String} bottom The bottom CSS property value
7891          * @return {Roo.Element} this
7892          */
7893         setBottom : function(bottom){
7894             this.setStyle("bottom", this.addUnits(bottom));
7895             return this;
7896         },
7897
7898         /**
7899          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7900          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7901          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7902          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7903          * @return {Roo.Element} this
7904          */
7905         setXY : function(pos, animate){
7906             if(!animate || !A){
7907                 D.setXY(this.dom, pos);
7908             }else{
7909                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7910             }
7911             return this;
7912         },
7913
7914         /**
7915          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7916          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7917          * @param {Number} x X value for new position (coordinates are page-based)
7918          * @param {Number} y Y value for new position (coordinates are page-based)
7919          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920          * @return {Roo.Element} this
7921          */
7922         setLocation : function(x, y, animate){
7923             this.setXY([x, y], this.preanim(arguments, 2));
7924             return this;
7925         },
7926
7927         /**
7928          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7929          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7930          * @param {Number} x X value for new position (coordinates are page-based)
7931          * @param {Number} y Y value for new position (coordinates are page-based)
7932          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         moveTo : function(x, y, animate){
7936             this.setXY([x, y], this.preanim(arguments, 2));
7937             return this;
7938         },
7939
7940         /**
7941          * Returns the region of the given element.
7942          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7943          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7944          */
7945         getRegion : function(){
7946             return D.getRegion(this.dom);
7947         },
7948
7949         /**
7950          * Returns the offset height of the element
7951          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7952          * @return {Number} The element's height
7953          */
7954         getHeight : function(contentHeight){
7955             var h = this.dom.offsetHeight || 0;
7956             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7957         },
7958
7959         /**
7960          * Returns the offset width of the element
7961          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7962          * @return {Number} The element's width
7963          */
7964         getWidth : function(contentWidth){
7965             var w = this.dom.offsetWidth || 0;
7966             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7967         },
7968
7969         /**
7970          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7971          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7972          * if a height has not been set using CSS.
7973          * @return {Number}
7974          */
7975         getComputedHeight : function(){
7976             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7977             if(!h){
7978                 h = parseInt(this.getStyle('height'), 10) || 0;
7979                 if(!this.isBorderBox()){
7980                     h += this.getFrameWidth('tb');
7981                 }
7982             }
7983             return h;
7984         },
7985
7986         /**
7987          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7988          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7989          * if a width has not been set using CSS.
7990          * @return {Number}
7991          */
7992         getComputedWidth : function(){
7993             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7994             if(!w){
7995                 w = parseInt(this.getStyle('width'), 10) || 0;
7996                 if(!this.isBorderBox()){
7997                     w += this.getFrameWidth('lr');
7998                 }
7999             }
8000             return w;
8001         },
8002
8003         /**
8004          * Returns the size of the element.
8005          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8006          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8007          */
8008         getSize : function(contentSize){
8009             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8010         },
8011
8012         /**
8013          * Returns the width and height of the viewport.
8014          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8015          */
8016         getViewSize : function(){
8017             var d = this.dom, doc = document, aw = 0, ah = 0;
8018             if(d == doc || d == doc.body){
8019                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8020             }else{
8021                 return {
8022                     width : d.clientWidth,
8023                     height: d.clientHeight
8024                 };
8025             }
8026         },
8027
8028         /**
8029          * Returns the value of the "value" attribute
8030          * @param {Boolean} asNumber true to parse the value as a number
8031          * @return {String/Number}
8032          */
8033         getValue : function(asNumber){
8034             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8035         },
8036
8037         // private
8038         adjustWidth : function(width){
8039             if(typeof width == "number"){
8040                 if(this.autoBoxAdjust && !this.isBorderBox()){
8041                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8042                 }
8043                 if(width < 0){
8044                     width = 0;
8045                 }
8046             }
8047             return width;
8048         },
8049
8050         // private
8051         adjustHeight : function(height){
8052             if(typeof height == "number"){
8053                if(this.autoBoxAdjust && !this.isBorderBox()){
8054                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8055                }
8056                if(height < 0){
8057                    height = 0;
8058                }
8059             }
8060             return height;
8061         },
8062
8063         /**
8064          * Set the width of the element
8065          * @param {Number} width The new width
8066          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8067          * @return {Roo.Element} this
8068          */
8069         setWidth : function(width, animate){
8070             width = this.adjustWidth(width);
8071             if(!animate || !A){
8072                 this.dom.style.width = this.addUnits(width);
8073             }else{
8074                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8075             }
8076             return this;
8077         },
8078
8079         /**
8080          * Set the height of the element
8081          * @param {Number} height The new height
8082          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083          * @return {Roo.Element} this
8084          */
8085          setHeight : function(height, animate){
8086             height = this.adjustHeight(height);
8087             if(!animate || !A){
8088                 this.dom.style.height = this.addUnits(height);
8089             }else{
8090                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8091             }
8092             return this;
8093         },
8094
8095         /**
8096          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8097          * @param {Number} width The new width
8098          * @param {Number} height The new height
8099          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100          * @return {Roo.Element} this
8101          */
8102          setSize : function(width, height, animate){
8103             if(typeof width == "object"){ // in case of object from getSize()
8104                 height = width.height; width = width.width;
8105             }
8106             width = this.adjustWidth(width); height = this.adjustHeight(height);
8107             if(!animate || !A){
8108                 this.dom.style.width = this.addUnits(width);
8109                 this.dom.style.height = this.addUnits(height);
8110             }else{
8111                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8112             }
8113             return this;
8114         },
8115
8116         /**
8117          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8118          * @param {Number} x X value for new position (coordinates are page-based)
8119          * @param {Number} y Y value for new position (coordinates are page-based)
8120          * @param {Number} width The new width
8121          * @param {Number} height The new height
8122          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8123          * @return {Roo.Element} this
8124          */
8125         setBounds : function(x, y, width, height, animate){
8126             if(!animate || !A){
8127                 this.setSize(width, height);
8128                 this.setLocation(x, y);
8129             }else{
8130                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8131                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8132                               this.preanim(arguments, 4), 'motion');
8133             }
8134             return this;
8135         },
8136
8137         /**
8138          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8139          * @param {Roo.lib.Region} region The region to fill
8140          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8141          * @return {Roo.Element} this
8142          */
8143         setRegion : function(region, animate){
8144             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8145             return this;
8146         },
8147
8148         /**
8149          * Appends an event handler
8150          *
8151          * @param {String}   eventName     The type of event to append
8152          * @param {Function} fn        The method the event invokes
8153          * @param {Object} scope       (optional) The scope (this object) of the fn
8154          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8155          */
8156         addListener : function(eventName, fn, scope, options){
8157             if (this.dom) {
8158                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8159             }
8160         },
8161
8162         /**
8163          * Removes an event handler from this element
8164          * @param {String} eventName the type of event to remove
8165          * @param {Function} fn the method the event invokes
8166          * @return {Roo.Element} this
8167          */
8168         removeListener : function(eventName, fn){
8169             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8170             return this;
8171         },
8172
8173         /**
8174          * Removes all previous added listeners from this element
8175          * @return {Roo.Element} this
8176          */
8177         removeAllListeners : function(){
8178             E.purgeElement(this.dom);
8179             return this;
8180         },
8181
8182         relayEvent : function(eventName, observable){
8183             this.on(eventName, function(e){
8184                 observable.fireEvent(eventName, e);
8185             });
8186         },
8187
8188         /**
8189          * Set the opacity of the element
8190          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8191          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8192          * @return {Roo.Element} this
8193          */
8194          setOpacity : function(opacity, animate){
8195             if(!animate || !A){
8196                 var s = this.dom.style;
8197                 if(Roo.isIE){
8198                     s.zoom = 1;
8199                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8200                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8201                 }else{
8202                     s.opacity = opacity;
8203                 }
8204             }else{
8205                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8206             }
8207             return this;
8208         },
8209
8210         /**
8211          * Gets the left X coordinate
8212          * @param {Boolean} local True to get the local css position instead of page coordinate
8213          * @return {Number}
8214          */
8215         getLeft : function(local){
8216             if(!local){
8217                 return this.getX();
8218             }else{
8219                 return parseInt(this.getStyle("left"), 10) || 0;
8220             }
8221         },
8222
8223         /**
8224          * Gets the right X coordinate of the element (element X position + element width)
8225          * @param {Boolean} local True to get the local css position instead of page coordinate
8226          * @return {Number}
8227          */
8228         getRight : function(local){
8229             if(!local){
8230                 return this.getX() + this.getWidth();
8231             }else{
8232                 return (this.getLeft(true) + this.getWidth()) || 0;
8233             }
8234         },
8235
8236         /**
8237          * Gets the top Y coordinate
8238          * @param {Boolean} local True to get the local css position instead of page coordinate
8239          * @return {Number}
8240          */
8241         getTop : function(local) {
8242             if(!local){
8243                 return this.getY();
8244             }else{
8245                 return parseInt(this.getStyle("top"), 10) || 0;
8246             }
8247         },
8248
8249         /**
8250          * Gets the bottom Y coordinate of the element (element Y position + element height)
8251          * @param {Boolean} local True to get the local css position instead of page coordinate
8252          * @return {Number}
8253          */
8254         getBottom : function(local){
8255             if(!local){
8256                 return this.getY() + this.getHeight();
8257             }else{
8258                 return (this.getTop(true) + this.getHeight()) || 0;
8259             }
8260         },
8261
8262         /**
8263         * Initializes positioning on this element. If a desired position is not passed, it will make the
8264         * the element positioned relative IF it is not already positioned.
8265         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8266         * @param {Number} zIndex (optional) The zIndex to apply
8267         * @param {Number} x (optional) Set the page X position
8268         * @param {Number} y (optional) Set the page Y position
8269         */
8270         position : function(pos, zIndex, x, y){
8271             if(!pos){
8272                if(this.getStyle('position') == 'static'){
8273                    this.setStyle('position', 'relative');
8274                }
8275             }else{
8276                 this.setStyle("position", pos);
8277             }
8278             if(zIndex){
8279                 this.setStyle("z-index", zIndex);
8280             }
8281             if(x !== undefined && y !== undefined){
8282                 this.setXY([x, y]);
8283             }else if(x !== undefined){
8284                 this.setX(x);
8285             }else if(y !== undefined){
8286                 this.setY(y);
8287             }
8288         },
8289
8290         /**
8291         * Clear positioning back to the default when the document was loaded
8292         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8293         * @return {Roo.Element} this
8294          */
8295         clearPositioning : function(value){
8296             value = value ||'';
8297             this.setStyle({
8298                 "left": value,
8299                 "right": value,
8300                 "top": value,
8301                 "bottom": value,
8302                 "z-index": "",
8303                 "position" : "static"
8304             });
8305             return this;
8306         },
8307
8308         /**
8309         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8310         * snapshot before performing an update and then restoring the element.
8311         * @return {Object}
8312         */
8313         getPositioning : function(){
8314             var l = this.getStyle("left");
8315             var t = this.getStyle("top");
8316             return {
8317                 "position" : this.getStyle("position"),
8318                 "left" : l,
8319                 "right" : l ? "" : this.getStyle("right"),
8320                 "top" : t,
8321                 "bottom" : t ? "" : this.getStyle("bottom"),
8322                 "z-index" : this.getStyle("z-index")
8323             };
8324         },
8325
8326         /**
8327          * Gets the width of the border(s) for the specified side(s)
8328          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8329          * passing lr would get the border (l)eft width + the border (r)ight width.
8330          * @return {Number} The width of the sides passed added together
8331          */
8332         getBorderWidth : function(side){
8333             return this.addStyles(side, El.borders);
8334         },
8335
8336         /**
8337          * Gets the width of the padding(s) for the specified side(s)
8338          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8339          * passing lr would get the padding (l)eft + the padding (r)ight.
8340          * @return {Number} The padding of the sides passed added together
8341          */
8342         getPadding : function(side){
8343             return this.addStyles(side, El.paddings);
8344         },
8345
8346         /**
8347         * Set positioning with an object returned by getPositioning().
8348         * @param {Object} posCfg
8349         * @return {Roo.Element} this
8350          */
8351         setPositioning : function(pc){
8352             this.applyStyles(pc);
8353             if(pc.right == "auto"){
8354                 this.dom.style.right = "";
8355             }
8356             if(pc.bottom == "auto"){
8357                 this.dom.style.bottom = "";
8358             }
8359             return this;
8360         },
8361
8362         // private
8363         fixDisplay : function(){
8364             if(this.getStyle("display") == "none"){
8365                 this.setStyle("visibility", "hidden");
8366                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8367                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8368                     this.setStyle("display", "block");
8369                 }
8370             }
8371         },
8372
8373         /**
8374          * Quick set left and top adding default units
8375          * @param {String} left The left CSS property value
8376          * @param {String} top The top CSS property value
8377          * @return {Roo.Element} this
8378          */
8379          setLeftTop : function(left, top){
8380             this.dom.style.left = this.addUnits(left);
8381             this.dom.style.top = this.addUnits(top);
8382             return this;
8383         },
8384
8385         /**
8386          * Move this element relative to its current position.
8387          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8388          * @param {Number} distance How far to move the element in pixels
8389          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8390          * @return {Roo.Element} this
8391          */
8392          move : function(direction, distance, animate){
8393             var xy = this.getXY();
8394             direction = direction.toLowerCase();
8395             switch(direction){
8396                 case "l":
8397                 case "left":
8398                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8399                     break;
8400                case "r":
8401                case "right":
8402                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8403                     break;
8404                case "t":
8405                case "top":
8406                case "up":
8407                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8408                     break;
8409                case "b":
8410                case "bottom":
8411                case "down":
8412                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8413                     break;
8414             }
8415             return this;
8416         },
8417
8418         /**
8419          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8420          * @return {Roo.Element} this
8421          */
8422         clip : function(){
8423             if(!this.isClipped){
8424                this.isClipped = true;
8425                this.originalClip = {
8426                    "o": this.getStyle("overflow"),
8427                    "x": this.getStyle("overflow-x"),
8428                    "y": this.getStyle("overflow-y")
8429                };
8430                this.setStyle("overflow", "hidden");
8431                this.setStyle("overflow-x", "hidden");
8432                this.setStyle("overflow-y", "hidden");
8433             }
8434             return this;
8435         },
8436
8437         /**
8438          *  Return clipping (overflow) to original clipping before clip() was called
8439          * @return {Roo.Element} this
8440          */
8441         unclip : function(){
8442             if(this.isClipped){
8443                 this.isClipped = false;
8444                 var o = this.originalClip;
8445                 if(o.o){this.setStyle("overflow", o.o);}
8446                 if(o.x){this.setStyle("overflow-x", o.x);}
8447                 if(o.y){this.setStyle("overflow-y", o.y);}
8448             }
8449             return this;
8450         },
8451
8452
8453         /**
8454          * Gets the x,y coordinates specified by the anchor position on the element.
8455          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8456          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8457          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8458          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8459          * @return {Array} [x, y] An array containing the element's x and y coordinates
8460          */
8461         getAnchorXY : function(anchor, local, s){
8462             //Passing a different size is useful for pre-calculating anchors,
8463             //especially for anchored animations that change the el size.
8464
8465             var w, h, vp = false;
8466             if(!s){
8467                 var d = this.dom;
8468                 if(d == document.body || d == document){
8469                     vp = true;
8470                     w = D.getViewWidth(); h = D.getViewHeight();
8471                 }else{
8472                     w = this.getWidth(); h = this.getHeight();
8473                 }
8474             }else{
8475                 w = s.width;  h = s.height;
8476             }
8477             var x = 0, y = 0, r = Math.round;
8478             switch((anchor || "tl").toLowerCase()){
8479                 case "c":
8480                     x = r(w*.5);
8481                     y = r(h*.5);
8482                 break;
8483                 case "t":
8484                     x = r(w*.5);
8485                     y = 0;
8486                 break;
8487                 case "l":
8488                     x = 0;
8489                     y = r(h*.5);
8490                 break;
8491                 case "r":
8492                     x = w;
8493                     y = r(h*.5);
8494                 break;
8495                 case "b":
8496                     x = r(w*.5);
8497                     y = h;
8498                 break;
8499                 case "tl":
8500                     x = 0;
8501                     y = 0;
8502                 break;
8503                 case "bl":
8504                     x = 0;
8505                     y = h;
8506                 break;
8507                 case "br":
8508                     x = w;
8509                     y = h;
8510                 break;
8511                 case "tr":
8512                     x = w;
8513                     y = 0;
8514                 break;
8515             }
8516             if(local === true){
8517                 return [x, y];
8518             }
8519             if(vp){
8520                 var sc = this.getScroll();
8521                 return [x + sc.left, y + sc.top];
8522             }
8523             //Add the element's offset xy
8524             var o = this.getXY();
8525             return [x+o[0], y+o[1]];
8526         },
8527
8528         /**
8529          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8530          * supported position values.
8531          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8532          * @param {String} position The position to align to.
8533          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8534          * @return {Array} [x, y]
8535          */
8536         getAlignToXY : function(el, p, o){
8537             el = Roo.get(el);
8538             var d = this.dom;
8539             if(!el.dom){
8540                 throw "Element.alignTo with an element that doesn't exist";
8541             }
8542             var c = false; //constrain to viewport
8543             var p1 = "", p2 = "";
8544             o = o || [0,0];
8545
8546             if(!p){
8547                 p = "tl-bl";
8548             }else if(p == "?"){
8549                 p = "tl-bl?";
8550             }else if(p.indexOf("-") == -1){
8551                 p = "tl-" + p;
8552             }
8553             p = p.toLowerCase();
8554             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8555             if(!m){
8556                throw "Element.alignTo with an invalid alignment " + p;
8557             }
8558             p1 = m[1]; p2 = m[2]; c = !!m[3];
8559
8560             //Subtract the aligned el's internal xy from the target's offset xy
8561             //plus custom offset to get the aligned el's new offset xy
8562             var a1 = this.getAnchorXY(p1, true);
8563             var a2 = el.getAnchorXY(p2, false);
8564             var x = a2[0] - a1[0] + o[0];
8565             var y = a2[1] - a1[1] + o[1];
8566             if(c){
8567                 //constrain the aligned el to viewport if necessary
8568                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8569                 // 5px of margin for ie
8570                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8571
8572                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8573                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8574                 //otherwise swap the aligned el to the opposite border of the target.
8575                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8576                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8577                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8578                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8579
8580                var doc = document;
8581                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8582                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8583
8584                if((x+w) > dw + scrollX){
8585                     x = swapX ? r.left-w : dw+scrollX-w;
8586                 }
8587                if(x < scrollX){
8588                    x = swapX ? r.right : scrollX;
8589                }
8590                if((y+h) > dh + scrollY){
8591                     y = swapY ? r.top-h : dh+scrollY-h;
8592                 }
8593                if (y < scrollY){
8594                    y = swapY ? r.bottom : scrollY;
8595                }
8596             }
8597             return [x,y];
8598         },
8599
8600         // private
8601         getConstrainToXY : function(){
8602             var os = {top:0, left:0, bottom:0, right: 0};
8603
8604             return function(el, local, offsets, proposedXY){
8605                 el = Roo.get(el);
8606                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8607
8608                 var vw, vh, vx = 0, vy = 0;
8609                 if(el.dom == document.body || el.dom == document){
8610                     vw = Roo.lib.Dom.getViewWidth();
8611                     vh = Roo.lib.Dom.getViewHeight();
8612                 }else{
8613                     vw = el.dom.clientWidth;
8614                     vh = el.dom.clientHeight;
8615                     if(!local){
8616                         var vxy = el.getXY();
8617                         vx = vxy[0];
8618                         vy = vxy[1];
8619                     }
8620                 }
8621
8622                 var s = el.getScroll();
8623
8624                 vx += offsets.left + s.left;
8625                 vy += offsets.top + s.top;
8626
8627                 vw -= offsets.right;
8628                 vh -= offsets.bottom;
8629
8630                 var vr = vx+vw;
8631                 var vb = vy+vh;
8632
8633                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8634                 var x = xy[0], y = xy[1];
8635                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8636
8637                 // only move it if it needs it
8638                 var moved = false;
8639
8640                 // first validate right/bottom
8641                 if((x + w) > vr){
8642                     x = vr - w;
8643                     moved = true;
8644                 }
8645                 if((y + h) > vb){
8646                     y = vb - h;
8647                     moved = true;
8648                 }
8649                 // then make sure top/left isn't negative
8650                 if(x < vx){
8651                     x = vx;
8652                     moved = true;
8653                 }
8654                 if(y < vy){
8655                     y = vy;
8656                     moved = true;
8657                 }
8658                 return moved ? [x, y] : false;
8659             };
8660         }(),
8661
8662         // private
8663         adjustForConstraints : function(xy, parent, offsets){
8664             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8665         },
8666
8667         /**
8668          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8669          * document it aligns it to the viewport.
8670          * The position parameter is optional, and can be specified in any one of the following formats:
8671          * <ul>
8672          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8673          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8674          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8675          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8676          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8677          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8678          * </ul>
8679          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8680          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8681          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8682          * that specified in order to enforce the viewport constraints.
8683          * Following are all of the supported anchor positions:
8684     <pre>
8685     Value  Description
8686     -----  -----------------------------
8687     tl     The top left corner (default)
8688     t      The center of the top edge
8689     tr     The top right corner
8690     l      The center of the left edge
8691     c      In the center of the element
8692     r      The center of the right edge
8693     bl     The bottom left corner
8694     b      The center of the bottom edge
8695     br     The bottom right corner
8696     </pre>
8697     Example Usage:
8698     <pre><code>
8699     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8700     el.alignTo("other-el");
8701
8702     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8703     el.alignTo("other-el", "tr?");
8704
8705     // align the bottom right corner of el with the center left edge of other-el
8706     el.alignTo("other-el", "br-l?");
8707
8708     // align the center of el with the bottom left corner of other-el and
8709     // adjust the x position by -6 pixels (and the y position by 0)
8710     el.alignTo("other-el", "c-bl", [-6, 0]);
8711     </code></pre>
8712          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8713          * @param {String} position The position to align to.
8714          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8715          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8716          * @return {Roo.Element} this
8717          */
8718         alignTo : function(element, position, offsets, animate){
8719             var xy = this.getAlignToXY(element, position, offsets);
8720             this.setXY(xy, this.preanim(arguments, 3));
8721             return this;
8722         },
8723
8724         /**
8725          * Anchors an element to another element and realigns it when the window is resized.
8726          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8727          * @param {String} position The position to align to.
8728          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8729          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8730          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8731          * is a number, it is used as the buffer delay (defaults to 50ms).
8732          * @param {Function} callback The function to call after the animation finishes
8733          * @return {Roo.Element} this
8734          */
8735         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8736             var action = function(){
8737                 this.alignTo(el, alignment, offsets, animate);
8738                 Roo.callback(callback, this);
8739             };
8740             Roo.EventManager.onWindowResize(action, this);
8741             var tm = typeof monitorScroll;
8742             if(tm != 'undefined'){
8743                 Roo.EventManager.on(window, 'scroll', action, this,
8744                     {buffer: tm == 'number' ? monitorScroll : 50});
8745             }
8746             action.call(this); // align immediately
8747             return this;
8748         },
8749         /**
8750          * Clears any opacity settings from this element. Required in some cases for IE.
8751          * @return {Roo.Element} this
8752          */
8753         clearOpacity : function(){
8754             if (window.ActiveXObject) {
8755                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8756                     this.dom.style.filter = "";
8757                 }
8758             } else {
8759                 this.dom.style.opacity = "";
8760                 this.dom.style["-moz-opacity"] = "";
8761                 this.dom.style["-khtml-opacity"] = "";
8762             }
8763             return this;
8764         },
8765
8766         /**
8767          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8768          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8769          * @return {Roo.Element} this
8770          */
8771         hide : function(animate){
8772             this.setVisible(false, this.preanim(arguments, 0));
8773             return this;
8774         },
8775
8776         /**
8777         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8778         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8779          * @return {Roo.Element} this
8780          */
8781         show : function(animate){
8782             this.setVisible(true, this.preanim(arguments, 0));
8783             return this;
8784         },
8785
8786         /**
8787          * @private Test if size has a unit, otherwise appends the default
8788          */
8789         addUnits : function(size){
8790             return Roo.Element.addUnits(size, this.defaultUnit);
8791         },
8792
8793         /**
8794          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8795          * @return {Roo.Element} this
8796          */
8797         beginMeasure : function(){
8798             var el = this.dom;
8799             if(el.offsetWidth || el.offsetHeight){
8800                 return this; // offsets work already
8801             }
8802             var changed = [];
8803             var p = this.dom, b = document.body; // start with this element
8804             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8805                 var pe = Roo.get(p);
8806                 if(pe.getStyle('display') == 'none'){
8807                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8808                     p.style.visibility = "hidden";
8809                     p.style.display = "block";
8810                 }
8811                 p = p.parentNode;
8812             }
8813             this._measureChanged = changed;
8814             return this;
8815
8816         },
8817
8818         /**
8819          * Restores displays to before beginMeasure was called
8820          * @return {Roo.Element} this
8821          */
8822         endMeasure : function(){
8823             var changed = this._measureChanged;
8824             if(changed){
8825                 for(var i = 0, len = changed.length; i < len; i++) {
8826                     var r = changed[i];
8827                     r.el.style.visibility = r.visibility;
8828                     r.el.style.display = "none";
8829                 }
8830                 this._measureChanged = null;
8831             }
8832             return this;
8833         },
8834
8835         /**
8836         * Update the innerHTML of this element, optionally searching for and processing scripts
8837         * @param {String} html The new HTML
8838         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8839         * @param {Function} callback For async script loading you can be noticed when the update completes
8840         * @return {Roo.Element} this
8841          */
8842         update : function(html, loadScripts, callback){
8843             if(typeof html == "undefined"){
8844                 html = "";
8845             }
8846             if(loadScripts !== true){
8847                 this.dom.innerHTML = html;
8848                 if(typeof callback == "function"){
8849                     callback();
8850                 }
8851                 return this;
8852             }
8853             var id = Roo.id();
8854             var dom = this.dom;
8855
8856             html += '<span id="' + id + '"></span>';
8857
8858             E.onAvailable(id, function(){
8859                 var hd = document.getElementsByTagName("head")[0];
8860                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8861                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8862                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8863
8864                 var match;
8865                 while(match = re.exec(html)){
8866                     var attrs = match[1];
8867                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8868                     if(srcMatch && srcMatch[2]){
8869                        var s = document.createElement("script");
8870                        s.src = srcMatch[2];
8871                        var typeMatch = attrs.match(typeRe);
8872                        if(typeMatch && typeMatch[2]){
8873                            s.type = typeMatch[2];
8874                        }
8875                        hd.appendChild(s);
8876                     }else if(match[2] && match[2].length > 0){
8877                         if(window.execScript) {
8878                            window.execScript(match[2]);
8879                         } else {
8880                             /**
8881                              * eval:var:id
8882                              * eval:var:dom
8883                              * eval:var:html
8884                              * 
8885                              */
8886                            window.eval(match[2]);
8887                         }
8888                     }
8889                 }
8890                 var el = document.getElementById(id);
8891                 if(el){el.parentNode.removeChild(el);}
8892                 if(typeof callback == "function"){
8893                     callback();
8894                 }
8895             });
8896             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8897             return this;
8898         },
8899
8900         /**
8901          * Direct access to the UpdateManager update() method (takes the same parameters).
8902          * @param {String/Function} url The url for this request or a function to call to get the url
8903          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
8904          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8905          * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8906          * @return {Roo.Element} this
8907          */
8908         load : function(){
8909             var um = this.getUpdateManager();
8910             um.update.apply(um, arguments);
8911             return this;
8912         },
8913
8914         /**
8915         * Gets this element's UpdateManager
8916         * @return {Roo.UpdateManager} The UpdateManager
8917         */
8918         getUpdateManager : function(){
8919             if(!this.updateManager){
8920                 this.updateManager = new Roo.UpdateManager(this);
8921             }
8922             return this.updateManager;
8923         },
8924
8925         /**
8926          * Disables text selection for this element (normalized across browsers)
8927          * @return {Roo.Element} this
8928          */
8929         unselectable : function(){
8930             this.dom.unselectable = "on";
8931             this.swallowEvent("selectstart", true);
8932             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8933             this.addClass("x-unselectable");
8934             return this;
8935         },
8936
8937         /**
8938         * Calculates the x, y to center this element on the screen
8939         * @return {Array} The x, y values [x, y]
8940         */
8941         getCenterXY : function(){
8942             return this.getAlignToXY(document, 'c-c');
8943         },
8944
8945         /**
8946         * Centers the Element in either the viewport, or another Element.
8947         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8948         */
8949         center : function(centerIn){
8950             this.alignTo(centerIn || document, 'c-c');
8951             return this;
8952         },
8953
8954         /**
8955          * Tests various css rules/browsers to determine if this element uses a border box
8956          * @return {Boolean}
8957          */
8958         isBorderBox : function(){
8959             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8960         },
8961
8962         /**
8963          * Return a box {x, y, width, height} that can be used to set another elements
8964          * size/location to match this element.
8965          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8966          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8967          * @return {Object} box An object in the format {x, y, width, height}
8968          */
8969         getBox : function(contentBox, local){
8970             var xy;
8971             if(!local){
8972                 xy = this.getXY();
8973             }else{
8974                 var left = parseInt(this.getStyle("left"), 10) || 0;
8975                 var top = parseInt(this.getStyle("top"), 10) || 0;
8976                 xy = [left, top];
8977             }
8978             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8979             if(!contentBox){
8980                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8981             }else{
8982                 var l = this.getBorderWidth("l")+this.getPadding("l");
8983                 var r = this.getBorderWidth("r")+this.getPadding("r");
8984                 var t = this.getBorderWidth("t")+this.getPadding("t");
8985                 var b = this.getBorderWidth("b")+this.getPadding("b");
8986                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8987             }
8988             bx.right = bx.x + bx.width;
8989             bx.bottom = bx.y + bx.height;
8990             return bx;
8991         },
8992
8993         /**
8994          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8995          for more information about the sides.
8996          * @param {String} sides
8997          * @return {Number}
8998          */
8999         getFrameWidth : function(sides, onlyContentBox){
9000             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9001         },
9002
9003         /**
9004          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
9005          * @param {Object} box The box to fill {x, y, width, height}
9006          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9007          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9008          * @return {Roo.Element} this
9009          */
9010         setBox : function(box, adjust, animate){
9011             var w = box.width, h = box.height;
9012             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9013                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9014                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9015             }
9016             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9017             return this;
9018         },
9019
9020         /**
9021          * Forces the browser to repaint this element
9022          * @return {Roo.Element} this
9023          */
9024          repaint : function(){
9025             var dom = this.dom;
9026             this.addClass("x-repaint");
9027             setTimeout(function(){
9028                 Roo.get(dom).removeClass("x-repaint");
9029             }, 1);
9030             return this;
9031         },
9032
9033         /**
9034          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9035          * then it returns the calculated width of the sides (see getPadding)
9036          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9037          * @return {Object/Number}
9038          */
9039         getMargins : function(side){
9040             if(!side){
9041                 return {
9042                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9043                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9044                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9045                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9046                 };
9047             }else{
9048                 return this.addStyles(side, El.margins);
9049              }
9050         },
9051
9052         // private
9053         addStyles : function(sides, styles){
9054             var val = 0, v, w;
9055             for(var i = 0, len = sides.length; i < len; i++){
9056                 v = this.getStyle(styles[sides.charAt(i)]);
9057                 if(v){
9058                      w = parseInt(v, 10);
9059                      if(w){ val += w; }
9060                 }
9061             }
9062             return val;
9063         },
9064
9065         /**
9066          * Creates a proxy element of this element
9067          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9068          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9069          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9070          * @return {Roo.Element} The new proxy element
9071          */
9072         createProxy : function(config, renderTo, matchBox){
9073             if(renderTo){
9074                 renderTo = Roo.getDom(renderTo);
9075             }else{
9076                 renderTo = document.body;
9077             }
9078             config = typeof config == "object" ?
9079                 config : {tag : "div", cls: config};
9080             var proxy = Roo.DomHelper.append(renderTo, config, true);
9081             if(matchBox){
9082                proxy.setBox(this.getBox());
9083             }
9084             return proxy;
9085         },
9086
9087         /**
9088          * Puts a mask over this element to disable user interaction. Requires core.css.
9089          * This method can only be applied to elements which accept child nodes.
9090          * @param {String} msg (optional) A message to display in the mask
9091          * @param {String} msgCls (optional) A css class to apply to the msg element
9092          * @return {Element} The mask  element
9093          */
9094         mask : function(msg, msgCls)
9095         {
9096             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9097                 this.setStyle("position", "relative");
9098             }
9099             if(!this._mask){
9100                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9101             }
9102             this.addClass("x-masked");
9103             this._mask.setDisplayed(true);
9104             
9105             // we wander
9106             var z = 0;
9107             var dom = this.dom;
9108             while (dom && dom.style) {
9109                 if (!isNaN(parseInt(dom.style.zIndex))) {
9110                     z = Math.max(z, parseInt(dom.style.zIndex));
9111                 }
9112                 dom = dom.parentNode;
9113             }
9114             // if we are masking the body - then it hides everything..
9115             if (this.dom == document.body) {
9116                 z = 1000000;
9117                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9118                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9119             }
9120            
9121             if(typeof msg == 'string'){
9122                 if(!this._maskMsg){
9123                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9124                 }
9125                 var mm = this._maskMsg;
9126                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9127                 if (mm.dom.firstChild) { // weird IE issue?
9128                     mm.dom.firstChild.innerHTML = msg;
9129                 }
9130                 mm.setDisplayed(true);
9131                 mm.center(this);
9132                 mm.setStyle('z-index', z + 102);
9133             }
9134             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9135                 this._mask.setHeight(this.getHeight());
9136             }
9137             this._mask.setStyle('z-index', z + 100);
9138             
9139             return this._mask;
9140         },
9141
9142         /**
9143          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9144          * it is cached for reuse.
9145          */
9146         unmask : function(removeEl){
9147             if(this._mask){
9148                 if(removeEl === true){
9149                     this._mask.remove();
9150                     delete this._mask;
9151                     if(this._maskMsg){
9152                         this._maskMsg.remove();
9153                         delete this._maskMsg;
9154                     }
9155                 }else{
9156                     this._mask.setDisplayed(false);
9157                     if(this._maskMsg){
9158                         this._maskMsg.setDisplayed(false);
9159                     }
9160                 }
9161             }
9162             this.removeClass("x-masked");
9163         },
9164
9165         /**
9166          * Returns true if this element is masked
9167          * @return {Boolean}
9168          */
9169         isMasked : function(){
9170             return this._mask && this._mask.isVisible();
9171         },
9172
9173         /**
9174          * Creates an iframe shim for this element to keep selects and other windowed objects from
9175          * showing through.
9176          * @return {Roo.Element} The new shim element
9177          */
9178         createShim : function(){
9179             var el = document.createElement('iframe');
9180             el.frameBorder = 'no';
9181             el.className = 'roo-shim';
9182             if(Roo.isIE && Roo.isSecure){
9183                 el.src = Roo.SSL_SECURE_URL;
9184             }
9185             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9186             shim.autoBoxAdjust = false;
9187             return shim;
9188         },
9189
9190         /**
9191          * Removes this element from the DOM and deletes it from the cache
9192          */
9193         remove : function(){
9194             if(this.dom.parentNode){
9195                 this.dom.parentNode.removeChild(this.dom);
9196             }
9197             delete El.cache[this.dom.id];
9198         },
9199
9200         /**
9201          * Sets up event handlers to add and remove a css class when the mouse is over this element
9202          * @param {String} className
9203          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9204          * mouseout events for children elements
9205          * @return {Roo.Element} this
9206          */
9207         addClassOnOver : function(className, preventFlicker){
9208             this.on("mouseover", function(){
9209                 Roo.fly(this, '_internal').addClass(className);
9210             }, this.dom);
9211             var removeFn = function(e){
9212                 if(preventFlicker !== true || !e.within(this, true)){
9213                     Roo.fly(this, '_internal').removeClass(className);
9214                 }
9215             };
9216             this.on("mouseout", removeFn, this.dom);
9217             return this;
9218         },
9219
9220         /**
9221          * Sets up event handlers to add and remove a css class when this element has the focus
9222          * @param {String} className
9223          * @return {Roo.Element} this
9224          */
9225         addClassOnFocus : function(className){
9226             this.on("focus", function(){
9227                 Roo.fly(this, '_internal').addClass(className);
9228             }, this.dom);
9229             this.on("blur", function(){
9230                 Roo.fly(this, '_internal').removeClass(className);
9231             }, this.dom);
9232             return this;
9233         },
9234         /**
9235          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9236          * @param {String} className
9237          * @return {Roo.Element} this
9238          */
9239         addClassOnClick : function(className){
9240             var dom = this.dom;
9241             this.on("mousedown", function(){
9242                 Roo.fly(dom, '_internal').addClass(className);
9243                 var d = Roo.get(document);
9244                 var fn = function(){
9245                     Roo.fly(dom, '_internal').removeClass(className);
9246                     d.removeListener("mouseup", fn);
9247                 };
9248                 d.on("mouseup", fn);
9249             });
9250             return this;
9251         },
9252
9253         /**
9254          * Stops the specified event from bubbling and optionally prevents the default action
9255          * @param {String} eventName
9256          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9257          * @return {Roo.Element} this
9258          */
9259         swallowEvent : function(eventName, preventDefault){
9260             var fn = function(e){
9261                 e.stopPropagation();
9262                 if(preventDefault){
9263                     e.preventDefault();
9264                 }
9265             };
9266             if(eventName instanceof Array){
9267                 for(var i = 0, len = eventName.length; i < len; i++){
9268                      this.on(eventName[i], fn);
9269                 }
9270                 return this;
9271             }
9272             this.on(eventName, fn);
9273             return this;
9274         },
9275
9276         /**
9277          * @private
9278          */
9279       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9280
9281         /**
9282          * Sizes this element to its parent element's dimensions performing
9283          * neccessary box adjustments.
9284          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9285          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9286          * @return {Roo.Element} this
9287          */
9288         fitToParent : function(monitorResize, targetParent) {
9289           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9290           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9291           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9292             return;
9293           }
9294           var p = Roo.get(targetParent || this.dom.parentNode);
9295           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9296           if (monitorResize === true) {
9297             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9298             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9299           }
9300           return this;
9301         },
9302
9303         /**
9304          * Gets the next sibling, skipping text nodes
9305          * @return {HTMLElement} The next sibling or null
9306          */
9307         getNextSibling : function(){
9308             var n = this.dom.nextSibling;
9309             while(n && n.nodeType != 1){
9310                 n = n.nextSibling;
9311             }
9312             return n;
9313         },
9314
9315         /**
9316          * Gets the previous sibling, skipping text nodes
9317          * @return {HTMLElement} The previous sibling or null
9318          */
9319         getPrevSibling : function(){
9320             var n = this.dom.previousSibling;
9321             while(n && n.nodeType != 1){
9322                 n = n.previousSibling;
9323             }
9324             return n;
9325         },
9326
9327
9328         /**
9329          * Appends the passed element(s) to this element
9330          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9331          * @return {Roo.Element} this
9332          */
9333         appendChild: function(el){
9334             el = Roo.get(el);
9335             el.appendTo(this);
9336             return this;
9337         },
9338
9339         /**
9340          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9341          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9342          * automatically generated with the specified attributes.
9343          * @param {HTMLElement} insertBefore (optional) a child element of this element
9344          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9345          * @return {Roo.Element} The new child element
9346          */
9347         createChild: function(config, insertBefore, returnDom){
9348             config = config || {tag:'div'};
9349             if(insertBefore){
9350                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9351             }
9352             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9353         },
9354
9355         /**
9356          * Appends this element to the passed element
9357          * @param {String/HTMLElement/Element} el The new parent element
9358          * @return {Roo.Element} this
9359          */
9360         appendTo: function(el){
9361             el = Roo.getDom(el);
9362             el.appendChild(this.dom);
9363             return this;
9364         },
9365
9366         /**
9367          * Inserts this element before the passed element in the DOM
9368          * @param {String/HTMLElement/Element} el The element to insert before
9369          * @return {Roo.Element} this
9370          */
9371         insertBefore: function(el){
9372             el = Roo.getDom(el);
9373             el.parentNode.insertBefore(this.dom, el);
9374             return this;
9375         },
9376
9377         /**
9378          * Inserts this element after the passed element in the DOM
9379          * @param {String/HTMLElement/Element} el The element to insert after
9380          * @return {Roo.Element} this
9381          */
9382         insertAfter: function(el){
9383             el = Roo.getDom(el);
9384             el.parentNode.insertBefore(this.dom, el.nextSibling);
9385             return this;
9386         },
9387
9388         /**
9389          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9390          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9391          * @return {Roo.Element} The new child
9392          */
9393         insertFirst: function(el, returnDom){
9394             el = el || {};
9395             if(typeof el == 'object' && !el.nodeType){ // dh config
9396                 return this.createChild(el, this.dom.firstChild, returnDom);
9397             }else{
9398                 el = Roo.getDom(el);
9399                 this.dom.insertBefore(el, this.dom.firstChild);
9400                 return !returnDom ? Roo.get(el) : el;
9401             }
9402         },
9403
9404         /**
9405          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9406          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9407          * @param {String} where (optional) 'before' or 'after' defaults to before
9408          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9409          * @return {Roo.Element} the inserted Element
9410          */
9411         insertSibling: function(el, where, returnDom){
9412             where = where ? where.toLowerCase() : 'before';
9413             el = el || {};
9414             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9415
9416             if(typeof el == 'object' && !el.nodeType){ // dh config
9417                 if(where == 'after' && !this.dom.nextSibling){
9418                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9419                 }else{
9420                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9421                 }
9422
9423             }else{
9424                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9425                             where == 'before' ? this.dom : this.dom.nextSibling);
9426                 if(!returnDom){
9427                     rt = Roo.get(rt);
9428                 }
9429             }
9430             return rt;
9431         },
9432
9433         /**
9434          * Creates and wraps this element with another element
9435          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9436          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9437          * @return {HTMLElement/Element} The newly created wrapper element
9438          */
9439         wrap: function(config, returnDom){
9440             if(!config){
9441                 config = {tag: "div"};
9442             }
9443             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9444             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9445             return newEl;
9446         },
9447
9448         /**
9449          * Replaces the passed element with this element
9450          * @param {String/HTMLElement/Element} el The element to replace
9451          * @return {Roo.Element} this
9452          */
9453         replace: function(el){
9454             el = Roo.get(el);
9455             this.insertBefore(el);
9456             el.remove();
9457             return this;
9458         },
9459
9460         /**
9461          * Inserts an html fragment into this element
9462          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9463          * @param {String} html The HTML fragment
9464          * @param {Boolean} returnEl True to return an Roo.Element
9465          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9466          */
9467         insertHtml : function(where, html, returnEl){
9468             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9469             return returnEl ? Roo.get(el) : el;
9470         },
9471
9472         /**
9473          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9474          * @param {Object} o The object with the attributes
9475          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9476          * @return {Roo.Element} this
9477          */
9478         set : function(o, useSet){
9479             var el = this.dom;
9480             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9481             for(var attr in o){
9482                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9483                 if(attr=="cls"){
9484                     el.className = o["cls"];
9485                 }else{
9486                     if(useSet) {
9487                         el.setAttribute(attr, o[attr]);
9488                     } else {
9489                         el[attr] = o[attr];
9490                     }
9491                 }
9492             }
9493             if(o.style){
9494                 Roo.DomHelper.applyStyles(el, o.style);
9495             }
9496             return this;
9497         },
9498
9499         /**
9500          * Convenience method for constructing a KeyMap
9501          * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9502          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9503          * @param {Function} fn The function to call
9504          * @param {Object} scope (optional) The scope of the function
9505          * @return {Roo.KeyMap} The KeyMap created
9506          */
9507         addKeyListener : function(key, fn, scope){
9508             var config;
9509             if(typeof key != "object" || key instanceof Array){
9510                 config = {
9511                     key: key,
9512                     fn: fn,
9513                     scope: scope
9514                 };
9515             }else{
9516                 config = {
9517                     key : key.key,
9518                     shift : key.shift,
9519                     ctrl : key.ctrl,
9520                     alt : key.alt,
9521                     fn: fn,
9522                     scope: scope
9523                 };
9524             }
9525             return new Roo.KeyMap(this, config);
9526         },
9527
9528         /**
9529          * Creates a KeyMap for this element
9530          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9531          * @return {Roo.KeyMap} The KeyMap created
9532          */
9533         addKeyMap : function(config){
9534             return new Roo.KeyMap(this, config);
9535         },
9536
9537         /**
9538          * Returns true if this element is scrollable.
9539          * @return {Boolean}
9540          */
9541          isScrollable : function(){
9542             var dom = this.dom;
9543             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9544         },
9545
9546         /**
9547          * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9548          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9549          * @param {Number} value The new scroll value
9550          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9551          * @return {Element} this
9552          */
9553
9554         scrollTo : function(side, value, animate){
9555             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9556             if(!animate || !A){
9557                 this.dom[prop] = value;
9558             }else{
9559                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9560                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9561             }
9562             return this;
9563         },
9564
9565         /**
9566          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9567          * within this element's scrollable range.
9568          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9569          * @param {Number} distance How far to scroll the element in pixels
9570          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9571          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9572          * was scrolled as far as it could go.
9573          */
9574          scroll : function(direction, distance, animate){
9575              if(!this.isScrollable()){
9576                  return;
9577              }
9578              var el = this.dom;
9579              var l = el.scrollLeft, t = el.scrollTop;
9580              var w = el.scrollWidth, h = el.scrollHeight;
9581              var cw = el.clientWidth, ch = el.clientHeight;
9582              direction = direction.toLowerCase();
9583              var scrolled = false;
9584              var a = this.preanim(arguments, 2);
9585              switch(direction){
9586                  case "l":
9587                  case "left":
9588                      if(w - l > cw){
9589                          var v = Math.min(l + distance, w-cw);
9590                          this.scrollTo("left", v, a);
9591                          scrolled = true;
9592                      }
9593                      break;
9594                 case "r":
9595                 case "right":
9596                      if(l > 0){
9597                          var v = Math.max(l - distance, 0);
9598                          this.scrollTo("left", v, a);
9599                          scrolled = true;
9600                      }
9601                      break;
9602                 case "t":
9603                 case "top":
9604                 case "up":
9605                      if(t > 0){
9606                          var v = Math.max(t - distance, 0);
9607                          this.scrollTo("top", v, a);
9608                          scrolled = true;
9609                      }
9610                      break;
9611                 case "b":
9612                 case "bottom":
9613                 case "down":
9614                      if(h - t > ch){
9615                          var v = Math.min(t + distance, h-ch);
9616                          this.scrollTo("top", v, a);
9617                          scrolled = true;
9618                      }
9619                      break;
9620              }
9621              return scrolled;
9622         },
9623
9624         /**
9625          * Translates the passed page coordinates into left/top css values for this element
9626          * @param {Number/Array} x The page x or an array containing [x, y]
9627          * @param {Number} y The page y
9628          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9629          */
9630         translatePoints : function(x, y){
9631             if(typeof x == 'object' || x instanceof Array){
9632                 y = x[1]; x = x[0];
9633             }
9634             var p = this.getStyle('position');
9635             var o = this.getXY();
9636
9637             var l = parseInt(this.getStyle('left'), 10);
9638             var t = parseInt(this.getStyle('top'), 10);
9639
9640             if(isNaN(l)){
9641                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9642             }
9643             if(isNaN(t)){
9644                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9645             }
9646
9647             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9648         },
9649
9650         /**
9651          * Returns the current scroll position of the element.
9652          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9653          */
9654         getScroll : function(){
9655             var d = this.dom, doc = document;
9656             if(d == doc || d == doc.body){
9657                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9658                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9659                 return {left: l, top: t};
9660             }else{
9661                 return {left: d.scrollLeft, top: d.scrollTop};
9662             }
9663         },
9664
9665         /**
9666          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9667          * are convert to standard 6 digit hex color.
9668          * @param {String} attr The css attribute
9669          * @param {String} defaultValue The default value to use when a valid color isn't found
9670          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9671          * YUI color anims.
9672          */
9673         getColor : function(attr, defaultValue, prefix){
9674             var v = this.getStyle(attr);
9675             if(!v || v == "transparent" || v == "inherit") {
9676                 return defaultValue;
9677             }
9678             var color = typeof prefix == "undefined" ? "#" : prefix;
9679             if(v.substr(0, 4) == "rgb("){
9680                 var rvs = v.slice(4, v.length -1).split(",");
9681                 for(var i = 0; i < 3; i++){
9682                     var h = parseInt(rvs[i]).toString(16);
9683                     if(h < 16){
9684                         h = "0" + h;
9685                     }
9686                     color += h;
9687                 }
9688             } else {
9689                 if(v.substr(0, 1) == "#"){
9690                     if(v.length == 4) {
9691                         for(var i = 1; i < 4; i++){
9692                             var c = v.charAt(i);
9693                             color +=  c + c;
9694                         }
9695                     }else if(v.length == 7){
9696                         color += v.substr(1);
9697                     }
9698                 }
9699             }
9700             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9701         },
9702
9703         /**
9704          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9705          * gradient background, rounded corners and a 4-way shadow.
9706          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9707          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9708          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9709          * @return {Roo.Element} this
9710          */
9711         boxWrap : function(cls){
9712             cls = cls || 'x-box';
9713             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9714             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9715             return el;
9716         },
9717
9718         /**
9719          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9720          * @param {String} namespace The namespace in which to look for the attribute
9721          * @param {String} name The attribute name
9722          * @return {String} The attribute value
9723          */
9724         getAttributeNS : Roo.isIE ? function(ns, name){
9725             var d = this.dom;
9726             var type = typeof d[ns+":"+name];
9727             if(type != 'undefined' && type != 'unknown'){
9728                 return d[ns+":"+name];
9729             }
9730             return d[name];
9731         } : function(ns, name){
9732             var d = this.dom;
9733             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9734         },
9735         
9736         
9737         /**
9738          * Sets or Returns the value the dom attribute value
9739          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9740          * @param {String} value (optional) The value to set the attribute to
9741          * @return {String} The attribute value
9742          */
9743         attr : function(name){
9744             if (arguments.length > 1) {
9745                 this.dom.setAttribute(name, arguments[1]);
9746                 return arguments[1];
9747             }
9748             if (typeof(name) == 'object') {
9749                 for(var i in name) {
9750                     this.attr(i, name[i]);
9751                 }
9752                 return name;
9753             }
9754             
9755             
9756             if (!this.dom.hasAttribute(name)) {
9757                 return undefined;
9758             }
9759             return this.dom.getAttribute(name);
9760         }
9761         
9762         
9763         
9764     };
9765
9766     var ep = El.prototype;
9767
9768     /**
9769      * Appends an event handler (Shorthand for addListener)
9770      * @param {String}   eventName     The type of event to append
9771      * @param {Function} fn        The method the event invokes
9772      * @param {Object} scope       (optional) The scope (this object) of the fn
9773      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9774      * @method
9775      */
9776     ep.on = ep.addListener;
9777         // backwards compat
9778     ep.mon = ep.addListener;
9779
9780     /**
9781      * Removes an event handler from this element (shorthand for removeListener)
9782      * @param {String} eventName the type of event to remove
9783      * @param {Function} fn the method the event invokes
9784      * @return {Roo.Element} this
9785      * @method
9786      */
9787     ep.un = ep.removeListener;
9788
9789     /**
9790      * true to automatically adjust width and height settings for box-model issues (default to true)
9791      */
9792     ep.autoBoxAdjust = true;
9793
9794     // private
9795     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9796
9797     // private
9798     El.addUnits = function(v, defaultUnit){
9799         if(v === "" || v == "auto"){
9800             return v;
9801         }
9802         if(v === undefined){
9803             return '';
9804         }
9805         if(typeof v == "number" || !El.unitPattern.test(v)){
9806             return v + (defaultUnit || 'px');
9807         }
9808         return v;
9809     };
9810
9811     // special markup used throughout Roo when box wrapping elements
9812     El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9813     /**
9814      * Visibility mode constant - Use visibility to hide element
9815      * @static
9816      * @type Number
9817      */
9818     El.VISIBILITY = 1;
9819     /**
9820      * Visibility mode constant - Use display to hide element
9821      * @static
9822      * @type Number
9823      */
9824     El.DISPLAY = 2;
9825
9826     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9827     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9828     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9829
9830
9831
9832     /**
9833      * @private
9834      */
9835     El.cache = {};
9836
9837     var docEl;
9838
9839     /**
9840      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9841      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9842      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9843      * @return {Element} The Element object
9844      * @static
9845      */
9846     El.get = function(el){
9847         var ex, elm, id;
9848         if(!el){ return null; }
9849         if(typeof el == "string"){ // element id
9850             if(!(elm = document.getElementById(el))){
9851                 return null;
9852             }
9853             if(ex = El.cache[el]){
9854                 ex.dom = elm;
9855             }else{
9856                 ex = El.cache[el] = new El(elm);
9857             }
9858             return ex;
9859         }else if(el.tagName){ // dom element
9860             if(!(id = el.id)){
9861                 id = Roo.id(el);
9862             }
9863             if(ex = El.cache[id]){
9864                 ex.dom = el;
9865             }else{
9866                 ex = El.cache[id] = new El(el);
9867             }
9868             return ex;
9869         }else if(el instanceof El){
9870             if(el != docEl){
9871                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9872                                                               // catch case where it hasn't been appended
9873                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9874             }
9875             return el;
9876         }else if(el.isComposite){
9877             return el;
9878         }else if(el instanceof Array){
9879             return El.select(el);
9880         }else if(el == document){
9881             // create a bogus element object representing the document object
9882             if(!docEl){
9883                 var f = function(){};
9884                 f.prototype = El.prototype;
9885                 docEl = new f();
9886                 docEl.dom = document;
9887             }
9888             return docEl;
9889         }
9890         return null;
9891     };
9892
9893     // private
9894     El.uncache = function(el){
9895         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9896             if(a[i]){
9897                 delete El.cache[a[i].id || a[i]];
9898             }
9899         }
9900     };
9901
9902     // private
9903     // Garbage collection - uncache elements/purge listeners on orphaned elements
9904     // so we don't hold a reference and cause the browser to retain them
9905     El.garbageCollect = function(){
9906         if(!Roo.enableGarbageCollector){
9907             clearInterval(El.collectorThread);
9908             return;
9909         }
9910         for(var eid in El.cache){
9911             var el = El.cache[eid], d = el.dom;
9912             // -------------------------------------------------------
9913             // Determining what is garbage:
9914             // -------------------------------------------------------
9915             // !d
9916             // dom node is null, definitely garbage
9917             // -------------------------------------------------------
9918             // !d.parentNode
9919             // no parentNode == direct orphan, definitely garbage
9920             // -------------------------------------------------------
9921             // !d.offsetParent && !document.getElementById(eid)
9922             // display none elements have no offsetParent so we will
9923             // also try to look it up by it's id. However, check
9924             // offsetParent first so we don't do unneeded lookups.
9925             // This enables collection of elements that are not orphans
9926             // directly, but somewhere up the line they have an orphan
9927             // parent.
9928             // -------------------------------------------------------
9929             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9930                 delete El.cache[eid];
9931                 if(d && Roo.enableListenerCollection){
9932                     E.purgeElement(d);
9933                 }
9934             }
9935         }
9936     }
9937     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9938
9939
9940     // dom is optional
9941     El.Flyweight = function(dom){
9942         this.dom = dom;
9943     };
9944     El.Flyweight.prototype = El.prototype;
9945
9946     El._flyweights = {};
9947     /**
9948      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9949      * the dom node can be overwritten by other code.
9950      * @param {String/HTMLElement} el The dom node or id
9951      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9952      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9953      * @static
9954      * @return {Element} The shared Element object
9955      */
9956     El.fly = function(el, named){
9957         named = named || '_global';
9958         el = Roo.getDom(el);
9959         if(!el){
9960             return null;
9961         }
9962         if(!El._flyweights[named]){
9963             El._flyweights[named] = new El.Flyweight();
9964         }
9965         El._flyweights[named].dom = el;
9966         return El._flyweights[named];
9967     };
9968
9969     /**
9970      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9971      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9972      * Shorthand of {@link Roo.Element#get}
9973      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9974      * @return {Element} The Element object
9975      * @member Roo
9976      * @method get
9977      */
9978     Roo.get = El.get;
9979     /**
9980      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9981      * the dom node can be overwritten by other code.
9982      * Shorthand of {@link Roo.Element#fly}
9983      * @param {String/HTMLElement} el The dom node or id
9984      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9985      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9986      * @static
9987      * @return {Element} The shared Element object
9988      * @member Roo
9989      * @method fly
9990      */
9991     Roo.fly = El.fly;
9992
9993     // speedy lookup for elements never to box adjust
9994     var noBoxAdjust = Roo.isStrict ? {
9995         select:1
9996     } : {
9997         input:1, select:1, textarea:1
9998     };
9999     if(Roo.isIE || Roo.isGecko){
10000         noBoxAdjust['button'] = 1;
10001     }
10002
10003
10004     Roo.EventManager.on(window, 'unload', function(){
10005         delete El.cache;
10006         delete El._flyweights;
10007     });
10008 })();
10009
10010
10011
10012
10013 if(Roo.DomQuery){
10014     Roo.Element.selectorFunction = Roo.DomQuery.select;
10015 }
10016
10017 Roo.Element.select = function(selector, unique, root){
10018     var els;
10019     if(typeof selector == "string"){
10020         els = Roo.Element.selectorFunction(selector, root);
10021     }else if(selector.length !== undefined){
10022         els = selector;
10023     }else{
10024         throw "Invalid selector";
10025     }
10026     if(unique === true){
10027         return new Roo.CompositeElement(els);
10028     }else{
10029         return new Roo.CompositeElementLite(els);
10030     }
10031 };
10032 /**
10033  * Selects elements based on the passed CSS selector to enable working on them as 1.
10034  * @param {String/Array} selector The CSS selector or an array of elements
10035  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10036  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10037  * @return {CompositeElementLite/CompositeElement}
10038  * @member Roo
10039  * @method select
10040  */
10041 Roo.select = Roo.Element.select;
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056 /*
10057  * Based on:
10058  * Ext JS Library 1.1.1
10059  * Copyright(c) 2006-2007, Ext JS, LLC.
10060  *
10061  * Originally Released Under LGPL - original licence link has changed is not relivant.
10062  *
10063  * Fork - LGPL
10064  * <script type="text/javascript">
10065  */
10066
10067
10068
10069 //Notifies Element that fx methods are available
10070 Roo.enableFx = true;
10071
10072 /**
10073  * @class Roo.Fx
10074  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10075  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10076  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10077  * Element effects to work.</p><br/>
10078  *
10079  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10080  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10081  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10082  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10083  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10084  * expected results and should be done with care.</p><br/>
10085  *
10086  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10087  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10088 <pre>
10089 Value  Description
10090 -----  -----------------------------
10091 tl     The top left corner
10092 t      The center of the top edge
10093 tr     The top right corner
10094 l      The center of the left edge
10095 r      The center of the right edge
10096 bl     The bottom left corner
10097 b      The center of the bottom edge
10098 br     The bottom right corner
10099 </pre>
10100  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10101  * below are common options that can be passed to any Fx method.</b>
10102  * @cfg {Function} callback A function called when the effect is finished
10103  * @cfg {Object} scope The scope of the effect function
10104  * @cfg {String} easing A valid Easing value for the effect
10105  * @cfg {String} afterCls A css class to apply after the effect
10106  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10107  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10108  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10109  * effects that end with the element being visually hidden, ignored otherwise)
10110  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10111  * a function which returns such a specification that will be applied to the Element after the effect finishes
10112  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10113  * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10114  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10115  */
10116 Roo.Fx = {
10117         /**
10118          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10119          * origin for the slide effect.  This function automatically handles wrapping the element with
10120          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10121          * Usage:
10122          *<pre><code>
10123 // default: slide the element in from the top
10124 el.slideIn();
10125
10126 // custom: slide the element in from the right with a 2-second duration
10127 el.slideIn('r', { duration: 2 });
10128
10129 // common config options shown with default values
10130 el.slideIn('t', {
10131     easing: 'easeOut',
10132     duration: .5
10133 });
10134 </code></pre>
10135          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10136          * @param {Object} options (optional) Object literal with any of the Fx config options
10137          * @return {Roo.Element} The Element
10138          */
10139     slideIn : function(anchor, o){
10140         var el = this.getFxEl();
10141         o = o || {};
10142
10143         el.queueFx(o, function(){
10144
10145             anchor = anchor || "t";
10146
10147             // fix display to visibility
10148             this.fixDisplay();
10149
10150             // restore values after effect
10151             var r = this.getFxRestore();
10152             var b = this.getBox();
10153             // fixed size for slide
10154             this.setSize(b);
10155
10156             // wrap if needed
10157             var wrap = this.fxWrap(r.pos, o, "hidden");
10158
10159             var st = this.dom.style;
10160             st.visibility = "visible";
10161             st.position = "absolute";
10162
10163             // clear out temp styles after slide and unwrap
10164             var after = function(){
10165                 el.fxUnwrap(wrap, r.pos, o);
10166                 st.width = r.width;
10167                 st.height = r.height;
10168                 el.afterFx(o);
10169             };
10170             // time to calc the positions
10171             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10172
10173             switch(anchor.toLowerCase()){
10174                 case "t":
10175                     wrap.setSize(b.width, 0);
10176                     st.left = st.bottom = "0";
10177                     a = {height: bh};
10178                 break;
10179                 case "l":
10180                     wrap.setSize(0, b.height);
10181                     st.right = st.top = "0";
10182                     a = {width: bw};
10183                 break;
10184                 case "r":
10185                     wrap.setSize(0, b.height);
10186                     wrap.setX(b.right);
10187                     st.left = st.top = "0";
10188                     a = {width: bw, points: pt};
10189                 break;
10190                 case "b":
10191                     wrap.setSize(b.width, 0);
10192                     wrap.setY(b.bottom);
10193                     st.left = st.top = "0";
10194                     a = {height: bh, points: pt};
10195                 break;
10196                 case "tl":
10197                     wrap.setSize(0, 0);
10198                     st.right = st.bottom = "0";
10199                     a = {width: bw, height: bh};
10200                 break;
10201                 case "bl":
10202                     wrap.setSize(0, 0);
10203                     wrap.setY(b.y+b.height);
10204                     st.right = st.top = "0";
10205                     a = {width: bw, height: bh, points: pt};
10206                 break;
10207                 case "br":
10208                     wrap.setSize(0, 0);
10209                     wrap.setXY([b.right, b.bottom]);
10210                     st.left = st.top = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213                 case "tr":
10214                     wrap.setSize(0, 0);
10215                     wrap.setX(b.x+b.width);
10216                     st.left = st.bottom = "0";
10217                     a = {width: bw, height: bh, points: pt};
10218                 break;
10219             }
10220             this.dom.style.visibility = "visible";
10221             wrap.show();
10222
10223             arguments.callee.anim = wrap.fxanim(a,
10224                 o,
10225                 'motion',
10226                 .5,
10227                 'easeOut', after);
10228         });
10229         return this;
10230     },
10231     
10232         /**
10233          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10234          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10235          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10236          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10237          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10238          * Usage:
10239          *<pre><code>
10240 // default: slide the element out to the top
10241 el.slideOut();
10242
10243 // custom: slide the element out to the right with a 2-second duration
10244 el.slideOut('r', { duration: 2 });
10245
10246 // common config options shown with default values
10247 el.slideOut('t', {
10248     easing: 'easeOut',
10249     duration: .5,
10250     remove: false,
10251     useDisplay: false
10252 });
10253 </code></pre>
10254          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10255          * @param {Object} options (optional) Object literal with any of the Fx config options
10256          * @return {Roo.Element} The Element
10257          */
10258     slideOut : function(anchor, o){
10259         var el = this.getFxEl();
10260         o = o || {};
10261
10262         el.queueFx(o, function(){
10263
10264             anchor = anchor || "t";
10265
10266             // restore values after effect
10267             var r = this.getFxRestore();
10268             
10269             var b = this.getBox();
10270             // fixed size for slide
10271             this.setSize(b);
10272
10273             // wrap if needed
10274             var wrap = this.fxWrap(r.pos, o, "visible");
10275
10276             var st = this.dom.style;
10277             st.visibility = "visible";
10278             st.position = "absolute";
10279
10280             wrap.setSize(b);
10281
10282             var after = function(){
10283                 if(o.useDisplay){
10284                     el.setDisplayed(false);
10285                 }else{
10286                     el.hide();
10287                 }
10288
10289                 el.fxUnwrap(wrap, r.pos, o);
10290
10291                 st.width = r.width;
10292                 st.height = r.height;
10293
10294                 el.afterFx(o);
10295             };
10296
10297             var a, zero = {to: 0};
10298             switch(anchor.toLowerCase()){
10299                 case "t":
10300                     st.left = st.bottom = "0";
10301                     a = {height: zero};
10302                 break;
10303                 case "l":
10304                     st.right = st.top = "0";
10305                     a = {width: zero};
10306                 break;
10307                 case "r":
10308                     st.left = st.top = "0";
10309                     a = {width: zero, points: {to:[b.right, b.y]}};
10310                 break;
10311                 case "b":
10312                     st.left = st.top = "0";
10313                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10314                 break;
10315                 case "tl":
10316                     st.right = st.bottom = "0";
10317                     a = {width: zero, height: zero};
10318                 break;
10319                 case "bl":
10320                     st.right = st.top = "0";
10321                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10322                 break;
10323                 case "br":
10324                     st.left = st.top = "0";
10325                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10326                 break;
10327                 case "tr":
10328                     st.left = st.bottom = "0";
10329                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10330                 break;
10331             }
10332
10333             arguments.callee.anim = wrap.fxanim(a,
10334                 o,
10335                 'motion',
10336                 .5,
10337                 "easeOut", after);
10338         });
10339         return this;
10340     },
10341
10342         /**
10343          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10344          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10345          * The element must be removed from the DOM using the 'remove' config option if desired.
10346          * Usage:
10347          *<pre><code>
10348 // default
10349 el.puff();
10350
10351 // common config options shown with default values
10352 el.puff({
10353     easing: 'easeOut',
10354     duration: .5,
10355     remove: false,
10356     useDisplay: false
10357 });
10358 </code></pre>
10359          * @param {Object} options (optional) Object literal with any of the Fx config options
10360          * @return {Roo.Element} The Element
10361          */
10362     puff : function(o){
10363         var el = this.getFxEl();
10364         o = o || {};
10365
10366         el.queueFx(o, function(){
10367             this.clearOpacity();
10368             this.show();
10369
10370             // restore values after effect
10371             var r = this.getFxRestore();
10372             var st = this.dom.style;
10373
10374             var after = function(){
10375                 if(o.useDisplay){
10376                     el.setDisplayed(false);
10377                 }else{
10378                     el.hide();
10379                 }
10380
10381                 el.clearOpacity();
10382
10383                 el.setPositioning(r.pos);
10384                 st.width = r.width;
10385                 st.height = r.height;
10386                 st.fontSize = '';
10387                 el.afterFx(o);
10388             };
10389
10390             var width = this.getWidth();
10391             var height = this.getHeight();
10392
10393             arguments.callee.anim = this.fxanim({
10394                     width : {to: this.adjustWidth(width * 2)},
10395                     height : {to: this.adjustHeight(height * 2)},
10396                     points : {by: [-(width * .5), -(height * .5)]},
10397                     opacity : {to: 0},
10398                     fontSize: {to:200, unit: "%"}
10399                 },
10400                 o,
10401                 'motion',
10402                 .5,
10403                 "easeOut", after);
10404         });
10405         return this;
10406     },
10407
10408         /**
10409          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10410          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10411          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10412          * Usage:
10413          *<pre><code>
10414 // default
10415 el.switchOff();
10416
10417 // all config options shown with default values
10418 el.switchOff({
10419     easing: 'easeIn',
10420     duration: .3,
10421     remove: false,
10422     useDisplay: false
10423 });
10424 </code></pre>
10425          * @param {Object} options (optional) Object literal with any of the Fx config options
10426          * @return {Roo.Element} The Element
10427          */
10428     switchOff : function(o){
10429         var el = this.getFxEl();
10430         o = o || {};
10431
10432         el.queueFx(o, function(){
10433             this.clearOpacity();
10434             this.clip();
10435
10436             // restore values after effect
10437             var r = this.getFxRestore();
10438             var st = this.dom.style;
10439
10440             var after = function(){
10441                 if(o.useDisplay){
10442                     el.setDisplayed(false);
10443                 }else{
10444                     el.hide();
10445                 }
10446
10447                 el.clearOpacity();
10448                 el.setPositioning(r.pos);
10449                 st.width = r.width;
10450                 st.height = r.height;
10451
10452                 el.afterFx(o);
10453             };
10454
10455             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10456                 this.clearOpacity();
10457                 (function(){
10458                     this.fxanim({
10459                         height:{to:1},
10460                         points:{by:[0, this.getHeight() * .5]}
10461                     }, o, 'motion', 0.3, 'easeIn', after);
10462                 }).defer(100, this);
10463             });
10464         });
10465         return this;
10466     },
10467
10468     /**
10469      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10470      * changed using the "attr" config option) and then fading back to the original color. If no original
10471      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10472      * Usage:
10473 <pre><code>
10474 // default: highlight background to yellow
10475 el.highlight();
10476
10477 // custom: highlight foreground text to blue for 2 seconds
10478 el.highlight("0000ff", { attr: 'color', duration: 2 });
10479
10480 // common config options shown with default values
10481 el.highlight("ffff9c", {
10482     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10483     endColor: (current color) or "ffffff",
10484     easing: 'easeIn',
10485     duration: 1
10486 });
10487 </code></pre>
10488      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10489      * @param {Object} options (optional) Object literal with any of the Fx config options
10490      * @return {Roo.Element} The Element
10491      */ 
10492     highlight : function(color, o){
10493         var el = this.getFxEl();
10494         o = o || {};
10495
10496         el.queueFx(o, function(){
10497             color = color || "ffff9c";
10498             attr = o.attr || "backgroundColor";
10499
10500             this.clearOpacity();
10501             this.show();
10502
10503             var origColor = this.getColor(attr);
10504             var restoreColor = this.dom.style[attr];
10505             endColor = (o.endColor || origColor) || "ffffff";
10506
10507             var after = function(){
10508                 el.dom.style[attr] = restoreColor;
10509                 el.afterFx(o);
10510             };
10511
10512             var a = {};
10513             a[attr] = {from: color, to: endColor};
10514             arguments.callee.anim = this.fxanim(a,
10515                 o,
10516                 'color',
10517                 1,
10518                 'easeIn', after);
10519         });
10520         return this;
10521     },
10522
10523    /**
10524     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10525     * Usage:
10526 <pre><code>
10527 // default: a single light blue ripple
10528 el.frame();
10529
10530 // custom: 3 red ripples lasting 3 seconds total
10531 el.frame("ff0000", 3, { duration: 3 });
10532
10533 // common config options shown with default values
10534 el.frame("C3DAF9", 1, {
10535     duration: 1 //duration of entire animation (not each individual ripple)
10536     // Note: Easing is not configurable and will be ignored if included
10537 });
10538 </code></pre>
10539     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10540     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10541     * @param {Object} options (optional) Object literal with any of the Fx config options
10542     * @return {Roo.Element} The Element
10543     */
10544     frame : function(color, count, o){
10545         var el = this.getFxEl();
10546         o = o || {};
10547
10548         el.queueFx(o, function(){
10549             color = color || "#C3DAF9";
10550             if(color.length == 6){
10551                 color = "#" + color;
10552             }
10553             count = count || 1;
10554             duration = o.duration || 1;
10555             this.show();
10556
10557             var b = this.getBox();
10558             var animFn = function(){
10559                 var proxy = this.createProxy({
10560
10561                      style:{
10562                         visbility:"hidden",
10563                         position:"absolute",
10564                         "z-index":"35000", // yee haw
10565                         border:"0px solid " + color
10566                      }
10567                   });
10568                 var scale = Roo.isBorderBox ? 2 : 1;
10569                 proxy.animate({
10570                     top:{from:b.y, to:b.y - 20},
10571                     left:{from:b.x, to:b.x - 20},
10572                     borderWidth:{from:0, to:10},
10573                     opacity:{from:1, to:0},
10574                     height:{from:b.height, to:(b.height + (20*scale))},
10575                     width:{from:b.width, to:(b.width + (20*scale))}
10576                 }, duration, function(){
10577                     proxy.remove();
10578                 });
10579                 if(--count > 0){
10580                      animFn.defer((duration/2)*1000, this);
10581                 }else{
10582                     el.afterFx(o);
10583                 }
10584             };
10585             animFn.call(this);
10586         });
10587         return this;
10588     },
10589
10590    /**
10591     * Creates a pause before any subsequent queued effects begin.  If there are
10592     * no effects queued after the pause it will have no effect.
10593     * Usage:
10594 <pre><code>
10595 el.pause(1);
10596 </code></pre>
10597     * @param {Number} seconds The length of time to pause (in seconds)
10598     * @return {Roo.Element} The Element
10599     */
10600     pause : function(seconds){
10601         var el = this.getFxEl();
10602         var o = {};
10603
10604         el.queueFx(o, function(){
10605             setTimeout(function(){
10606                 el.afterFx(o);
10607             }, seconds * 1000);
10608         });
10609         return this;
10610     },
10611
10612    /**
10613     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10614     * using the "endOpacity" config option.
10615     * Usage:
10616 <pre><code>
10617 // default: fade in from opacity 0 to 100%
10618 el.fadeIn();
10619
10620 // custom: fade in from opacity 0 to 75% over 2 seconds
10621 el.fadeIn({ endOpacity: .75, duration: 2});
10622
10623 // common config options shown with default values
10624 el.fadeIn({
10625     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10626     easing: 'easeOut',
10627     duration: .5
10628 });
10629 </code></pre>
10630     * @param {Object} options (optional) Object literal with any of the Fx config options
10631     * @return {Roo.Element} The Element
10632     */
10633     fadeIn : function(o){
10634         var el = this.getFxEl();
10635         o = o || {};
10636         el.queueFx(o, function(){
10637             this.setOpacity(0);
10638             this.fixDisplay();
10639             this.dom.style.visibility = 'visible';
10640             var to = o.endOpacity || 1;
10641             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10642                 o, null, .5, "easeOut", function(){
10643                 if(to == 1){
10644                     this.clearOpacity();
10645                 }
10646                 el.afterFx(o);
10647             });
10648         });
10649         return this;
10650     },
10651
10652    /**
10653     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10654     * using the "endOpacity" config option.
10655     * Usage:
10656 <pre><code>
10657 // default: fade out from the element's current opacity to 0
10658 el.fadeOut();
10659
10660 // custom: fade out from the element's current opacity to 25% over 2 seconds
10661 el.fadeOut({ endOpacity: .25, duration: 2});
10662
10663 // common config options shown with default values
10664 el.fadeOut({
10665     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10666     easing: 'easeOut',
10667     duration: .5
10668     remove: false,
10669     useDisplay: false
10670 });
10671 </code></pre>
10672     * @param {Object} options (optional) Object literal with any of the Fx config options
10673     * @return {Roo.Element} The Element
10674     */
10675     fadeOut : function(o){
10676         var el = this.getFxEl();
10677         o = o || {};
10678         el.queueFx(o, function(){
10679             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10680                 o, null, .5, "easeOut", function(){
10681                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10682                      this.dom.style.display = "none";
10683                 }else{
10684                      this.dom.style.visibility = "hidden";
10685                 }
10686                 this.clearOpacity();
10687                 el.afterFx(o);
10688             });
10689         });
10690         return this;
10691     },
10692
10693    /**
10694     * Animates the transition of an element's dimensions from a starting height/width
10695     * to an ending height/width.
10696     * Usage:
10697 <pre><code>
10698 // change height and width to 100x100 pixels
10699 el.scale(100, 100);
10700
10701 // common config options shown with default values.  The height and width will default to
10702 // the element's existing values if passed as null.
10703 el.scale(
10704     [element's width],
10705     [element's height], {
10706     easing: 'easeOut',
10707     duration: .35
10708 });
10709 </code></pre>
10710     * @param {Number} width  The new width (pass undefined to keep the original width)
10711     * @param {Number} height  The new height (pass undefined to keep the original height)
10712     * @param {Object} options (optional) Object literal with any of the Fx config options
10713     * @return {Roo.Element} The Element
10714     */
10715     scale : function(w, h, o){
10716         this.shift(Roo.apply({}, o, {
10717             width: w,
10718             height: h
10719         }));
10720         return this;
10721     },
10722
10723    /**
10724     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10725     * Any of these properties not specified in the config object will not be changed.  This effect 
10726     * requires that at least one new dimension, position or opacity setting must be passed in on
10727     * the config object in order for the function to have any effect.
10728     * Usage:
10729 <pre><code>
10730 // slide the element horizontally to x position 200 while changing the height and opacity
10731 el.shift({ x: 200, height: 50, opacity: .8 });
10732
10733 // common config options shown with default values.
10734 el.shift({
10735     width: [element's width],
10736     height: [element's height],
10737     x: [element's x position],
10738     y: [element's y position],
10739     opacity: [element's opacity],
10740     easing: 'easeOut',
10741     duration: .35
10742 });
10743 </code></pre>
10744     * @param {Object} options  Object literal with any of the Fx config options
10745     * @return {Roo.Element} The Element
10746     */
10747     shift : function(o){
10748         var el = this.getFxEl();
10749         o = o || {};
10750         el.queueFx(o, function(){
10751             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10752             if(w !== undefined){
10753                 a.width = {to: this.adjustWidth(w)};
10754             }
10755             if(h !== undefined){
10756                 a.height = {to: this.adjustHeight(h)};
10757             }
10758             if(x !== undefined || y !== undefined){
10759                 a.points = {to: [
10760                     x !== undefined ? x : this.getX(),
10761                     y !== undefined ? y : this.getY()
10762                 ]};
10763             }
10764             if(op !== undefined){
10765                 a.opacity = {to: op};
10766             }
10767             if(o.xy !== undefined){
10768                 a.points = {to: o.xy};
10769             }
10770             arguments.callee.anim = this.fxanim(a,
10771                 o, 'motion', .35, "easeOut", function(){
10772                 el.afterFx(o);
10773             });
10774         });
10775         return this;
10776     },
10777
10778         /**
10779          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10780          * ending point of the effect.
10781          * Usage:
10782          *<pre><code>
10783 // default: slide the element downward while fading out
10784 el.ghost();
10785
10786 // custom: slide the element out to the right with a 2-second duration
10787 el.ghost('r', { duration: 2 });
10788
10789 // common config options shown with default values
10790 el.ghost('b', {
10791     easing: 'easeOut',
10792     duration: .5
10793     remove: false,
10794     useDisplay: false
10795 });
10796 </code></pre>
10797          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10798          * @param {Object} options (optional) Object literal with any of the Fx config options
10799          * @return {Roo.Element} The Element
10800          */
10801     ghost : function(anchor, o){
10802         var el = this.getFxEl();
10803         o = o || {};
10804
10805         el.queueFx(o, function(){
10806             anchor = anchor || "b";
10807
10808             // restore values after effect
10809             var r = this.getFxRestore();
10810             var w = this.getWidth(),
10811                 h = this.getHeight();
10812
10813             var st = this.dom.style;
10814
10815             var after = function(){
10816                 if(o.useDisplay){
10817                     el.setDisplayed(false);
10818                 }else{
10819                     el.hide();
10820                 }
10821
10822                 el.clearOpacity();
10823                 el.setPositioning(r.pos);
10824                 st.width = r.width;
10825                 st.height = r.height;
10826
10827                 el.afterFx(o);
10828             };
10829
10830             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10831             switch(anchor.toLowerCase()){
10832                 case "t":
10833                     pt.by = [0, -h];
10834                 break;
10835                 case "l":
10836                     pt.by = [-w, 0];
10837                 break;
10838                 case "r":
10839                     pt.by = [w, 0];
10840                 break;
10841                 case "b":
10842                     pt.by = [0, h];
10843                 break;
10844                 case "tl":
10845                     pt.by = [-w, -h];
10846                 break;
10847                 case "bl":
10848                     pt.by = [-w, h];
10849                 break;
10850                 case "br":
10851                     pt.by = [w, h];
10852                 break;
10853                 case "tr":
10854                     pt.by = [w, -h];
10855                 break;
10856             }
10857
10858             arguments.callee.anim = this.fxanim(a,
10859                 o,
10860                 'motion',
10861                 .5,
10862                 "easeOut", after);
10863         });
10864         return this;
10865     },
10866
10867         /**
10868          * Ensures that all effects queued after syncFx is called on the element are
10869          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10870          * @return {Roo.Element} The Element
10871          */
10872     syncFx : function(){
10873         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10874             block : false,
10875             concurrent : true,
10876             stopFx : false
10877         });
10878         return this;
10879     },
10880
10881         /**
10882          * Ensures that all effects queued after sequenceFx is called on the element are
10883          * run in sequence.  This is the opposite of {@link #syncFx}.
10884          * @return {Roo.Element} The Element
10885          */
10886     sequenceFx : function(){
10887         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10888             block : false,
10889             concurrent : false,
10890             stopFx : false
10891         });
10892         return this;
10893     },
10894
10895         /* @private */
10896     nextFx : function(){
10897         var ef = this.fxQueue[0];
10898         if(ef){
10899             ef.call(this);
10900         }
10901     },
10902
10903         /**
10904          * Returns true if the element has any effects actively running or queued, else returns false.
10905          * @return {Boolean} True if element has active effects, else false
10906          */
10907     hasActiveFx : function(){
10908         return this.fxQueue && this.fxQueue[0];
10909     },
10910
10911         /**
10912          * Stops any running effects and clears the element's internal effects queue if it contains
10913          * any additional effects that haven't started yet.
10914          * @return {Roo.Element} The Element
10915          */
10916     stopFx : function(){
10917         if(this.hasActiveFx()){
10918             var cur = this.fxQueue[0];
10919             if(cur && cur.anim && cur.anim.isAnimated()){
10920                 this.fxQueue = [cur]; // clear out others
10921                 cur.anim.stop(true);
10922             }
10923         }
10924         return this;
10925     },
10926
10927         /* @private */
10928     beforeFx : function(o){
10929         if(this.hasActiveFx() && !o.concurrent){
10930            if(o.stopFx){
10931                this.stopFx();
10932                return true;
10933            }
10934            return false;
10935         }
10936         return true;
10937     },
10938
10939         /**
10940          * Returns true if the element is currently blocking so that no other effect can be queued
10941          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10942          * used to ensure that an effect initiated by a user action runs to completion prior to the
10943          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10944          * @return {Boolean} True if blocking, else false
10945          */
10946     hasFxBlock : function(){
10947         var q = this.fxQueue;
10948         return q && q[0] && q[0].block;
10949     },
10950
10951         /* @private */
10952     queueFx : function(o, fn){
10953         if(!this.fxQueue){
10954             this.fxQueue = [];
10955         }
10956         if(!this.hasFxBlock()){
10957             Roo.applyIf(o, this.fxDefaults);
10958             if(!o.concurrent){
10959                 var run = this.beforeFx(o);
10960                 fn.block = o.block;
10961                 this.fxQueue.push(fn);
10962                 if(run){
10963                     this.nextFx();
10964                 }
10965             }else{
10966                 fn.call(this);
10967             }
10968         }
10969         return this;
10970     },
10971
10972         /* @private */
10973     fxWrap : function(pos, o, vis){
10974         var wrap;
10975         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10976             var wrapXY;
10977             if(o.fixPosition){
10978                 wrapXY = this.getXY();
10979             }
10980             var div = document.createElement("div");
10981             div.style.visibility = vis;
10982             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10983             wrap.setPositioning(pos);
10984             if(wrap.getStyle("position") == "static"){
10985                 wrap.position("relative");
10986             }
10987             this.clearPositioning('auto');
10988             wrap.clip();
10989             wrap.dom.appendChild(this.dom);
10990             if(wrapXY){
10991                 wrap.setXY(wrapXY);
10992             }
10993         }
10994         return wrap;
10995     },
10996
10997         /* @private */
10998     fxUnwrap : function(wrap, pos, o){
10999         this.clearPositioning();
11000         this.setPositioning(pos);
11001         if(!o.wrap){
11002             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11003             wrap.remove();
11004         }
11005     },
11006
11007         /* @private */
11008     getFxRestore : function(){
11009         var st = this.dom.style;
11010         return {pos: this.getPositioning(), width: st.width, height : st.height};
11011     },
11012
11013         /* @private */
11014     afterFx : function(o){
11015         if(o.afterStyle){
11016             this.applyStyles(o.afterStyle);
11017         }
11018         if(o.afterCls){
11019             this.addClass(o.afterCls);
11020         }
11021         if(o.remove === true){
11022             this.remove();
11023         }
11024         Roo.callback(o.callback, o.scope, [this]);
11025         if(!o.concurrent){
11026             this.fxQueue.shift();
11027             this.nextFx();
11028         }
11029     },
11030
11031         /* @private */
11032     getFxEl : function(){ // support for composite element fx
11033         return Roo.get(this.dom);
11034     },
11035
11036         /* @private */
11037     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11038         animType = animType || 'run';
11039         opt = opt || {};
11040         var anim = Roo.lib.Anim[animType](
11041             this.dom, args,
11042             (opt.duration || defaultDur) || .35,
11043             (opt.easing || defaultEase) || 'easeOut',
11044             function(){
11045                 Roo.callback(cb, this);
11046             },
11047             this
11048         );
11049         opt.anim = anim;
11050         return anim;
11051     }
11052 };
11053
11054 // backwords compat
11055 Roo.Fx.resize = Roo.Fx.scale;
11056
11057 //When included, Roo.Fx is automatically applied to Element so that all basic
11058 //effects are available directly via the Element API
11059 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11060  * Based on:
11061  * Ext JS Library 1.1.1
11062  * Copyright(c) 2006-2007, Ext JS, LLC.
11063  *
11064  * Originally Released Under LGPL - original licence link has changed is not relivant.
11065  *
11066  * Fork - LGPL
11067  * <script type="text/javascript">
11068  */
11069
11070
11071 /**
11072  * @class Roo.CompositeElement
11073  * Standard composite class. Creates a Roo.Element for every element in the collection.
11074  * <br><br>
11075  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11076  * actions will be performed on all the elements in this collection.</b>
11077  * <br><br>
11078  * All methods return <i>this</i> and can be chained.
11079  <pre><code>
11080  var els = Roo.select("#some-el div.some-class", true);
11081  // or select directly from an existing element
11082  var el = Roo.get('some-el');
11083  el.select('div.some-class', true);
11084
11085  els.setWidth(100); // all elements become 100 width
11086  els.hide(true); // all elements fade out and hide
11087  // or
11088  els.setWidth(100).hide(true);
11089  </code></pre>
11090  */
11091 Roo.CompositeElement = function(els){
11092     this.elements = [];
11093     this.addElements(els);
11094 };
11095 Roo.CompositeElement.prototype = {
11096     isComposite: true,
11097     addElements : function(els){
11098         if(!els) {
11099             return this;
11100         }
11101         if(typeof els == "string"){
11102             els = Roo.Element.selectorFunction(els);
11103         }
11104         var yels = this.elements;
11105         var index = yels.length-1;
11106         for(var i = 0, len = els.length; i < len; i++) {
11107                 yels[++index] = Roo.get(els[i]);
11108         }
11109         return this;
11110     },
11111
11112     /**
11113     * Clears this composite and adds the elements returned by the passed selector.
11114     * @param {String/Array} els A string CSS selector, an array of elements or an element
11115     * @return {CompositeElement} this
11116     */
11117     fill : function(els){
11118         this.elements = [];
11119         this.add(els);
11120         return this;
11121     },
11122
11123     /**
11124     * Filters this composite to only elements that match the passed selector.
11125     * @param {String} selector A string CSS selector
11126     * @param {Boolean} inverse return inverse filter (not matches)
11127     * @return {CompositeElement} this
11128     */
11129     filter : function(selector, inverse){
11130         var els = [];
11131         inverse = inverse || false;
11132         this.each(function(el){
11133             var match = inverse ? !el.is(selector) : el.is(selector);
11134             if(match){
11135                 els[els.length] = el.dom;
11136             }
11137         });
11138         this.fill(els);
11139         return this;
11140     },
11141
11142     invoke : function(fn, args){
11143         var els = this.elements;
11144         for(var i = 0, len = els.length; i < len; i++) {
11145                 Roo.Element.prototype[fn].apply(els[i], args);
11146         }
11147         return this;
11148     },
11149     /**
11150     * Adds elements to this composite.
11151     * @param {String/Array} els A string CSS selector, an array of elements or an element
11152     * @return {CompositeElement} this
11153     */
11154     add : function(els){
11155         if(typeof els == "string"){
11156             this.addElements(Roo.Element.selectorFunction(els));
11157         }else if(els.length !== undefined){
11158             this.addElements(els);
11159         }else{
11160             this.addElements([els]);
11161         }
11162         return this;
11163     },
11164     /**
11165     * Calls the passed function passing (el, this, index) for each element in this composite.
11166     * @param {Function} fn The function to call
11167     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11168     * @return {CompositeElement} this
11169     */
11170     each : function(fn, scope){
11171         var els = this.elements;
11172         for(var i = 0, len = els.length; i < len; i++){
11173             if(fn.call(scope || els[i], els[i], this, i) === false) {
11174                 break;
11175             }
11176         }
11177         return this;
11178     },
11179
11180     /**
11181      * Returns the Element object at the specified index
11182      * @param {Number} index
11183      * @return {Roo.Element}
11184      */
11185     item : function(index){
11186         return this.elements[index] || null;
11187     },
11188
11189     /**
11190      * Returns the first Element
11191      * @return {Roo.Element}
11192      */
11193     first : function(){
11194         return this.item(0);
11195     },
11196
11197     /**
11198      * Returns the last Element
11199      * @return {Roo.Element}
11200      */
11201     last : function(){
11202         return this.item(this.elements.length-1);
11203     },
11204
11205     /**
11206      * Returns the number of elements in this composite
11207      * @return Number
11208      */
11209     getCount : function(){
11210         return this.elements.length;
11211     },
11212
11213     /**
11214      * Returns true if this composite contains the passed element
11215      * @return Boolean
11216      */
11217     contains : function(el){
11218         return this.indexOf(el) !== -1;
11219     },
11220
11221     /**
11222      * Returns true if this composite contains the passed element
11223      * @return Boolean
11224      */
11225     indexOf : function(el){
11226         return this.elements.indexOf(Roo.get(el));
11227     },
11228
11229
11230     /**
11231     * Removes the specified element(s).
11232     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11233     * or an array of any of those.
11234     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11235     * @return {CompositeElement} this
11236     */
11237     removeElement : function(el, removeDom){
11238         if(el instanceof Array){
11239             for(var i = 0, len = el.length; i < len; i++){
11240                 this.removeElement(el[i]);
11241             }
11242             return this;
11243         }
11244         var index = typeof el == 'number' ? el : this.indexOf(el);
11245         if(index !== -1){
11246             if(removeDom){
11247                 var d = this.elements[index];
11248                 if(d.dom){
11249                     d.remove();
11250                 }else{
11251                     d.parentNode.removeChild(d);
11252                 }
11253             }
11254             this.elements.splice(index, 1);
11255         }
11256         return this;
11257     },
11258
11259     /**
11260     * Replaces the specified element with the passed element.
11261     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11262     * to replace.
11263     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11264     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11265     * @return {CompositeElement} this
11266     */
11267     replaceElement : function(el, replacement, domReplace){
11268         var index = typeof el == 'number' ? el : this.indexOf(el);
11269         if(index !== -1){
11270             if(domReplace){
11271                 this.elements[index].replaceWith(replacement);
11272             }else{
11273                 this.elements.splice(index, 1, Roo.get(replacement))
11274             }
11275         }
11276         return this;
11277     },
11278
11279     /**
11280      * Removes all elements.
11281      */
11282     clear : function(){
11283         this.elements = [];
11284     }
11285 };
11286 (function(){
11287     Roo.CompositeElement.createCall = function(proto, fnName){
11288         if(!proto[fnName]){
11289             proto[fnName] = function(){
11290                 return this.invoke(fnName, arguments);
11291             };
11292         }
11293     };
11294     for(var fnName in Roo.Element.prototype){
11295         if(typeof Roo.Element.prototype[fnName] == "function"){
11296             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11297         }
11298     };
11299 })();
11300 /*
11301  * Based on:
11302  * Ext JS Library 1.1.1
11303  * Copyright(c) 2006-2007, Ext JS, LLC.
11304  *
11305  * Originally Released Under LGPL - original licence link has changed is not relivant.
11306  *
11307  * Fork - LGPL
11308  * <script type="text/javascript">
11309  */
11310
11311 /**
11312  * @class Roo.CompositeElementLite
11313  * @extends Roo.CompositeElement
11314  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11315  <pre><code>
11316  var els = Roo.select("#some-el div.some-class");
11317  // or select directly from an existing element
11318  var el = Roo.get('some-el');
11319  el.select('div.some-class');
11320
11321  els.setWidth(100); // all elements become 100 width
11322  els.hide(true); // all elements fade out and hide
11323  // or
11324  els.setWidth(100).hide(true);
11325  </code></pre><br><br>
11326  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11327  * actions will be performed on all the elements in this collection.</b>
11328  */
11329 Roo.CompositeElementLite = function(els){
11330     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11331     this.el = new Roo.Element.Flyweight();
11332 };
11333 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11334     addElements : function(els){
11335         if(els){
11336             if(els instanceof Array){
11337                 this.elements = this.elements.concat(els);
11338             }else{
11339                 var yels = this.elements;
11340                 var index = yels.length-1;
11341                 for(var i = 0, len = els.length; i < len; i++) {
11342                     yels[++index] = els[i];
11343                 }
11344             }
11345         }
11346         return this;
11347     },
11348     invoke : function(fn, args){
11349         var els = this.elements;
11350         var el = this.el;
11351         for(var i = 0, len = els.length; i < len; i++) {
11352             el.dom = els[i];
11353                 Roo.Element.prototype[fn].apply(el, args);
11354         }
11355         return this;
11356     },
11357     /**
11358      * Returns a flyweight Element of the dom element object at the specified index
11359      * @param {Number} index
11360      * @return {Roo.Element}
11361      */
11362     item : function(index){
11363         if(!this.elements[index]){
11364             return null;
11365         }
11366         this.el.dom = this.elements[index];
11367         return this.el;
11368     },
11369
11370     // fixes scope with flyweight
11371     addListener : function(eventName, handler, scope, opt){
11372         var els = this.elements;
11373         for(var i = 0, len = els.length; i < len; i++) {
11374             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11375         }
11376         return this;
11377     },
11378
11379     /**
11380     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11381     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11382     * a reference to the dom node, use el.dom.</b>
11383     * @param {Function} fn The function to call
11384     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11385     * @return {CompositeElement} this
11386     */
11387     each : function(fn, scope){
11388         var els = this.elements;
11389         var el = this.el;
11390         for(var i = 0, len = els.length; i < len; i++){
11391             el.dom = els[i];
11392                 if(fn.call(scope || el, el, this, i) === false){
11393                 break;
11394             }
11395         }
11396         return this;
11397     },
11398
11399     indexOf : function(el){
11400         return this.elements.indexOf(Roo.getDom(el));
11401     },
11402
11403     replaceElement : function(el, replacement, domReplace){
11404         var index = typeof el == 'number' ? el : this.indexOf(el);
11405         if(index !== -1){
11406             replacement = Roo.getDom(replacement);
11407             if(domReplace){
11408                 var d = this.elements[index];
11409                 d.parentNode.insertBefore(replacement, d);
11410                 d.parentNode.removeChild(d);
11411             }
11412             this.elements.splice(index, 1, replacement);
11413         }
11414         return this;
11415     }
11416 });
11417 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11418
11419 /*
11420  * Based on:
11421  * Ext JS Library 1.1.1
11422  * Copyright(c) 2006-2007, Ext JS, LLC.
11423  *
11424  * Originally Released Under LGPL - original licence link has changed is not relivant.
11425  *
11426  * Fork - LGPL
11427  * <script type="text/javascript">
11428  */
11429
11430  
11431
11432 /**
11433  * @class Roo.data.Connection
11434  * @extends Roo.util.Observable
11435  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11436  * either to a configured URL, or to a URL specified at request time.<br><br>
11437  * <p>
11438  * Requests made by this class are asynchronous, and will return immediately. No data from
11439  * the server will be available to the statement immediately following the {@link #request} call.
11440  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11441  * <p>
11442  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11443  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11444  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11445  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11446  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11447  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11448  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11449  * standard DOM methods.
11450  * @constructor
11451  * @param {Object} config a configuration object.
11452  */
11453 Roo.data.Connection = function(config){
11454     Roo.apply(this, config);
11455     this.addEvents({
11456         /**
11457          * @event beforerequest
11458          * Fires before a network request is made to retrieve a data object.
11459          * @param {Connection} conn This Connection object.
11460          * @param {Object} options The options config object passed to the {@link #request} method.
11461          */
11462         "beforerequest" : true,
11463         /**
11464          * @event requestcomplete
11465          * Fires if the request was successfully completed.
11466          * @param {Connection} conn This Connection object.
11467          * @param {Object} response The XHR object containing the response data.
11468          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11469          * @param {Object} options The options config object passed to the {@link #request} method.
11470          */
11471         "requestcomplete" : true,
11472         /**
11473          * @event requestexception
11474          * Fires if an error HTTP status was returned from the server.
11475          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11476          * @param {Connection} conn This Connection object.
11477          * @param {Object} response The XHR object containing the response data.
11478          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11479          * @param {Object} options The options config object passed to the {@link #request} method.
11480          */
11481         "requestexception" : true
11482     });
11483     Roo.data.Connection.superclass.constructor.call(this);
11484 };
11485
11486 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11487     /**
11488      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11489      */
11490     /**
11491      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11492      * extra parameters to each request made by this object. (defaults to undefined)
11493      */
11494     /**
11495      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11496      *  to each request made by this object. (defaults to undefined)
11497      */
11498     /**
11499      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11500      */
11501     /**
11502      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11503      */
11504     timeout : 30000,
11505     /**
11506      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11507      * @type Boolean
11508      */
11509     autoAbort:false,
11510
11511     /**
11512      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11513      * @type Boolean
11514      */
11515     disableCaching: true,
11516
11517     /**
11518      * Sends an HTTP request to a remote server.
11519      * @param {Object} options An object which may contain the following properties:<ul>
11520      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11521      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11522      * request, a url encoded string or a function to call to get either.</li>
11523      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11524      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11525      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11526      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11527      * <li>options {Object} The parameter to the request call.</li>
11528      * <li>success {Boolean} True if the request succeeded.</li>
11529      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11530      * </ul></li>
11531      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11532      * The callback is passed the following parameters:<ul>
11533      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11534      * <li>options {Object} The parameter to the request call.</li>
11535      * </ul></li>
11536      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11537      * The callback is passed the following parameters:<ul>
11538      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11539      * <li>options {Object} The parameter to the request call.</li>
11540      * </ul></li>
11541      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11542      * for the callback function. Defaults to the browser window.</li>
11543      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11544      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11545      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11546      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11547      * params for the post data. Any params will be appended to the URL.</li>
11548      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11549      * </ul>
11550      * @return {Number} transactionId
11551      */
11552     request : function(o){
11553         if(this.fireEvent("beforerequest", this, o) !== false){
11554             var p = o.params;
11555
11556             if(typeof p == "function"){
11557                 p = p.call(o.scope||window, o);
11558             }
11559             if(typeof p == "object"){
11560                 p = Roo.urlEncode(o.params);
11561             }
11562             if(this.extraParams){
11563                 var extras = Roo.urlEncode(this.extraParams);
11564                 p = p ? (p + '&' + extras) : extras;
11565             }
11566
11567             var url = o.url || this.url;
11568             if(typeof url == 'function'){
11569                 url = url.call(o.scope||window, o);
11570             }
11571
11572             if(o.form){
11573                 var form = Roo.getDom(o.form);
11574                 url = url || form.action;
11575
11576                 var enctype = form.getAttribute("enctype");
11577                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11578                     return this.doFormUpload(o, p, url);
11579                 }
11580                 var f = Roo.lib.Ajax.serializeForm(form);
11581                 p = p ? (p + '&' + f) : f;
11582             }
11583
11584             var hs = o.headers;
11585             if(this.defaultHeaders){
11586                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11587                 if(!o.headers){
11588                     o.headers = hs;
11589                 }
11590             }
11591
11592             var cb = {
11593                 success: this.handleResponse,
11594                 failure: this.handleFailure,
11595                 scope: this,
11596                 argument: {options: o},
11597                 timeout : o.timeout || this.timeout
11598             };
11599
11600             var method = o.method||this.method||(p ? "POST" : "GET");
11601
11602             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11603                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11604             }
11605
11606             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11607                 if(o.autoAbort){
11608                     this.abort();
11609                 }
11610             }else if(this.autoAbort !== false){
11611                 this.abort();
11612             }
11613
11614             if((method == 'GET' && p) || o.xmlData){
11615                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11616                 p = '';
11617             }
11618             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11619             return this.transId;
11620         }else{
11621             Roo.callback(o.callback, o.scope, [o, null, null]);
11622             return null;
11623         }
11624     },
11625
11626     /**
11627      * Determine whether this object has a request outstanding.
11628      * @param {Number} transactionId (Optional) defaults to the last transaction
11629      * @return {Boolean} True if there is an outstanding request.
11630      */
11631     isLoading : function(transId){
11632         if(transId){
11633             return Roo.lib.Ajax.isCallInProgress(transId);
11634         }else{
11635             return this.transId ? true : false;
11636         }
11637     },
11638
11639     /**
11640      * Aborts any outstanding request.
11641      * @param {Number} transactionId (Optional) defaults to the last transaction
11642      */
11643     abort : function(transId){
11644         if(transId || this.isLoading()){
11645             Roo.lib.Ajax.abort(transId || this.transId);
11646         }
11647     },
11648
11649     // private
11650     handleResponse : function(response){
11651         this.transId = false;
11652         var options = response.argument.options;
11653         response.argument = options ? options.argument : null;
11654         this.fireEvent("requestcomplete", this, response, options);
11655         Roo.callback(options.success, options.scope, [response, options]);
11656         Roo.callback(options.callback, options.scope, [options, true, response]);
11657     },
11658
11659     // private
11660     handleFailure : function(response, e){
11661         this.transId = false;
11662         var options = response.argument.options;
11663         response.argument = options ? options.argument : null;
11664         this.fireEvent("requestexception", this, response, options, e);
11665         Roo.callback(options.failure, options.scope, [response, options]);
11666         Roo.callback(options.callback, options.scope, [options, false, response]);
11667     },
11668
11669     // private
11670     doFormUpload : function(o, ps, url){
11671         var id = Roo.id();
11672         var frame = document.createElement('iframe');
11673         frame.id = id;
11674         frame.name = id;
11675         frame.className = 'x-hidden';
11676         if(Roo.isIE){
11677             frame.src = Roo.SSL_SECURE_URL;
11678         }
11679         document.body.appendChild(frame);
11680
11681         if(Roo.isIE){
11682            document.frames[id].name = id;
11683         }
11684
11685         var form = Roo.getDom(o.form);
11686         form.target = id;
11687         form.method = 'POST';
11688         form.enctype = form.encoding = 'multipart/form-data';
11689         if(url){
11690             form.action = url;
11691         }
11692
11693         var hiddens, hd;
11694         if(ps){ // add dynamic params
11695             hiddens = [];
11696             ps = Roo.urlDecode(ps, false);
11697             for(var k in ps){
11698                 if(ps.hasOwnProperty(k)){
11699                     hd = document.createElement('input');
11700                     hd.type = 'hidden';
11701                     hd.name = k;
11702                     hd.value = ps[k];
11703                     form.appendChild(hd);
11704                     hiddens.push(hd);
11705                 }
11706             }
11707         }
11708
11709         function cb(){
11710             var r = {  // bogus response object
11711                 responseText : '',
11712                 responseXML : null
11713             };
11714
11715             r.argument = o ? o.argument : null;
11716
11717             try { //
11718                 var doc;
11719                 if(Roo.isIE){
11720                     doc = frame.contentWindow.document;
11721                 }else {
11722                     doc = (frame.contentDocument || window.frames[id].document);
11723                 }
11724                 if(doc && doc.body){
11725                     r.responseText = doc.body.innerHTML;
11726                 }
11727                 if(doc && doc.XMLDocument){
11728                     r.responseXML = doc.XMLDocument;
11729                 }else {
11730                     r.responseXML = doc;
11731                 }
11732             }
11733             catch(e) {
11734                 // ignore
11735             }
11736
11737             Roo.EventManager.removeListener(frame, 'load', cb, this);
11738
11739             this.fireEvent("requestcomplete", this, r, o);
11740             Roo.callback(o.success, o.scope, [r, o]);
11741             Roo.callback(o.callback, o.scope, [o, true, r]);
11742
11743             setTimeout(function(){document.body.removeChild(frame);}, 100);
11744         }
11745
11746         Roo.EventManager.on(frame, 'load', cb, this);
11747         form.submit();
11748
11749         if(hiddens){ // remove dynamic params
11750             for(var i = 0, len = hiddens.length; i < len; i++){
11751                 form.removeChild(hiddens[i]);
11752             }
11753         }
11754     }
11755 });
11756 /*
11757  * Based on:
11758  * Ext JS Library 1.1.1
11759  * Copyright(c) 2006-2007, Ext JS, LLC.
11760  *
11761  * Originally Released Under LGPL - original licence link has changed is not relivant.
11762  *
11763  * Fork - LGPL
11764  * <script type="text/javascript">
11765  */
11766  
11767 /**
11768  * Global Ajax request class.
11769  * 
11770  * @class Roo.Ajax
11771  * @extends Roo.data.Connection
11772  * @static
11773  * 
11774  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11775  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11776  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11777  * @cfg {String} method (Optional)  The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11778  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11779  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11780  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11781  */
11782 Roo.Ajax = new Roo.data.Connection({
11783     // fix up the docs
11784     /**
11785      * @scope Roo.Ajax
11786      * @type {Boolear} 
11787      */
11788     autoAbort : false,
11789
11790     /**
11791      * Serialize the passed form into a url encoded string
11792      * @scope Roo.Ajax
11793      * @param {String/HTMLElement} form
11794      * @return {String}
11795      */
11796     serializeForm : function(form){
11797         return Roo.lib.Ajax.serializeForm(form);
11798     }
11799 });/*
11800  * Based on:
11801  * Ext JS Library 1.1.1
11802  * Copyright(c) 2006-2007, Ext JS, LLC.
11803  *
11804  * Originally Released Under LGPL - original licence link has changed is not relivant.
11805  *
11806  * Fork - LGPL
11807  * <script type="text/javascript">
11808  */
11809
11810  
11811 /**
11812  * @class Roo.UpdateManager
11813  * @extends Roo.util.Observable
11814  * Provides AJAX-style update for Element object.<br><br>
11815  * Usage:<br>
11816  * <pre><code>
11817  * // Get it from a Roo.Element object
11818  * var el = Roo.get("foo");
11819  * var mgr = el.getUpdateManager();
11820  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11821  * ...
11822  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11823  * <br>
11824  * // or directly (returns the same UpdateManager instance)
11825  * var mgr = new Roo.UpdateManager("myElementId");
11826  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11827  * mgr.on("update", myFcnNeedsToKnow);
11828  * <br>
11829    // short handed call directly from the element object
11830    Roo.get("foo").load({
11831         url: "bar.php",
11832         scripts:true,
11833         params: "for=bar",
11834         text: "Loading Foo..."
11835    });
11836  * </code></pre>
11837  * @constructor
11838  * Create new UpdateManager directly.
11839  * @param {String/HTMLElement/Roo.Element} el The element to update
11840  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11841  */
11842 Roo.UpdateManager = function(el, forceNew){
11843     el = Roo.get(el);
11844     if(!forceNew && el.updateManager){
11845         return el.updateManager;
11846     }
11847     /**
11848      * The Element object
11849      * @type Roo.Element
11850      */
11851     this.el = el;
11852     /**
11853      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11854      * @type String
11855      */
11856     this.defaultUrl = null;
11857
11858     this.addEvents({
11859         /**
11860          * @event beforeupdate
11861          * Fired before an update is made, return false from your handler and the update is cancelled.
11862          * @param {Roo.Element} el
11863          * @param {String/Object/Function} url
11864          * @param {String/Object} params
11865          */
11866         "beforeupdate": true,
11867         /**
11868          * @event update
11869          * Fired after successful update is made.
11870          * @param {Roo.Element} el
11871          * @param {Object} oResponseObject The response Object
11872          */
11873         "update": true,
11874         /**
11875          * @event failure
11876          * Fired on update failure.
11877          * @param {Roo.Element} el
11878          * @param {Object} oResponseObject The response Object
11879          */
11880         "failure": true
11881     });
11882     var d = Roo.UpdateManager.defaults;
11883     /**
11884      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11885      * @type String
11886      */
11887     this.sslBlankUrl = d.sslBlankUrl;
11888     /**
11889      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11890      * @type Boolean
11891      */
11892     this.disableCaching = d.disableCaching;
11893     /**
11894      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11895      * @type String
11896      */
11897     this.indicatorText = d.indicatorText;
11898     /**
11899      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11900      * @type String
11901      */
11902     this.showLoadIndicator = d.showLoadIndicator;
11903     /**
11904      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11905      * @type Number
11906      */
11907     this.timeout = d.timeout;
11908
11909     /**
11910      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11911      * @type Boolean
11912      */
11913     this.loadScripts = d.loadScripts;
11914
11915     /**
11916      * Transaction object of current executing transaction
11917      */
11918     this.transaction = null;
11919
11920     /**
11921      * @private
11922      */
11923     this.autoRefreshProcId = null;
11924     /**
11925      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11926      * @type Function
11927      */
11928     this.refreshDelegate = this.refresh.createDelegate(this);
11929     /**
11930      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11931      * @type Function
11932      */
11933     this.updateDelegate = this.update.createDelegate(this);
11934     /**
11935      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11936      * @type Function
11937      */
11938     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11939     /**
11940      * @private
11941      */
11942     this.successDelegate = this.processSuccess.createDelegate(this);
11943     /**
11944      * @private
11945      */
11946     this.failureDelegate = this.processFailure.createDelegate(this);
11947
11948     if(!this.renderer){
11949      /**
11950       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11951       */
11952     this.renderer = new Roo.UpdateManager.BasicRenderer();
11953     }
11954     
11955     Roo.UpdateManager.superclass.constructor.call(this);
11956 };
11957
11958 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11959     /**
11960      * Get the Element this UpdateManager is bound to
11961      * @return {Roo.Element} The element
11962      */
11963     getEl : function(){
11964         return this.el;
11965     },
11966     /**
11967      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11968      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11969 <pre><code>
11970 um.update({<br/>
11971     url: "your-url.php",<br/>
11972     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11973     callback: yourFunction,<br/>
11974     scope: yourObject, //(optional scope)  <br/>
11975     discardUrl: false, <br/>
11976     nocache: false,<br/>
11977     text: "Loading...",<br/>
11978     timeout: 30,<br/>
11979     scripts: false<br/>
11980 });
11981 </code></pre>
11982      * The only required property is url. The optional properties nocache, text and scripts
11983      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11984      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
11985      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11986      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11987      */
11988     update : function(url, params, callback, discardUrl){
11989         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11990             var method = this.method,
11991                 cfg;
11992             if(typeof url == "object"){ // must be config object
11993                 cfg = url;
11994                 url = cfg.url;
11995                 params = params || cfg.params;
11996                 callback = callback || cfg.callback;
11997                 discardUrl = discardUrl || cfg.discardUrl;
11998                 if(callback && cfg.scope){
11999                     callback = callback.createDelegate(cfg.scope);
12000                 }
12001                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12002                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12003                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12004                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12005                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12006             }
12007             this.showLoading();
12008             if(!discardUrl){
12009                 this.defaultUrl = url;
12010             }
12011             if(typeof url == "function"){
12012                 url = url.call(this);
12013             }
12014
12015             method = method || (params ? "POST" : "GET");
12016             if(method == "GET"){
12017                 url = this.prepareUrl(url);
12018             }
12019
12020             var o = Roo.apply(cfg ||{}, {
12021                 url : url,
12022                 params: params,
12023                 success: this.successDelegate,
12024                 failure: this.failureDelegate,
12025                 callback: undefined,
12026                 timeout: (this.timeout*1000),
12027                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12028             });
12029             Roo.log("updated manager called with timeout of " + o.timeout);
12030             this.transaction = Roo.Ajax.request(o);
12031         }
12032     },
12033
12034     /**
12035      * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
12036      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12037      * @param {String/HTMLElement} form The form Id or form element
12038      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12039      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12040      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12041      */
12042     formUpdate : function(form, url, reset, callback){
12043         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12044             if(typeof url == "function"){
12045                 url = url.call(this);
12046             }
12047             form = Roo.getDom(form);
12048             this.transaction = Roo.Ajax.request({
12049                 form: form,
12050                 url:url,
12051                 success: this.successDelegate,
12052                 failure: this.failureDelegate,
12053                 timeout: (this.timeout*1000),
12054                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12055             });
12056             this.showLoading.defer(1, this);
12057         }
12058     },
12059
12060     /**
12061      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12062      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12063      */
12064     refresh : function(callback){
12065         if(this.defaultUrl == null){
12066             return;
12067         }
12068         this.update(this.defaultUrl, null, callback, true);
12069     },
12070
12071     /**
12072      * Set this element to auto refresh.
12073      * @param {Number} interval How often to update (in seconds).
12074      * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
12075      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
12076      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12077      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12078      */
12079     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12080         if(refreshNow){
12081             this.update(url || this.defaultUrl, params, callback, true);
12082         }
12083         if(this.autoRefreshProcId){
12084             clearInterval(this.autoRefreshProcId);
12085         }
12086         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12087     },
12088
12089     /**
12090      * Stop auto refresh on this element.
12091      */
12092      stopAutoRefresh : function(){
12093         if(this.autoRefreshProcId){
12094             clearInterval(this.autoRefreshProcId);
12095             delete this.autoRefreshProcId;
12096         }
12097     },
12098
12099     isAutoRefreshing : function(){
12100        return this.autoRefreshProcId ? true : false;
12101     },
12102     /**
12103      * Called to update the element to "Loading" state. Override to perform custom action.
12104      */
12105     showLoading : function(){
12106         if(this.showLoadIndicator){
12107             this.el.update(this.indicatorText);
12108         }
12109     },
12110
12111     /**
12112      * Adds unique parameter to query string if disableCaching = true
12113      * @private
12114      */
12115     prepareUrl : function(url){
12116         if(this.disableCaching){
12117             var append = "_dc=" + (new Date().getTime());
12118             if(url.indexOf("?") !== -1){
12119                 url += "&" + append;
12120             }else{
12121                 url += "?" + append;
12122             }
12123         }
12124         return url;
12125     },
12126
12127     /**
12128      * @private
12129      */
12130     processSuccess : function(response){
12131         this.transaction = null;
12132         if(response.argument.form && response.argument.reset){
12133             try{ // put in try/catch since some older FF releases had problems with this
12134                 response.argument.form.reset();
12135             }catch(e){}
12136         }
12137         if(this.loadScripts){
12138             this.renderer.render(this.el, response, this,
12139                 this.updateComplete.createDelegate(this, [response]));
12140         }else{
12141             this.renderer.render(this.el, response, this);
12142             this.updateComplete(response);
12143         }
12144     },
12145
12146     updateComplete : function(response){
12147         this.fireEvent("update", this.el, response);
12148         if(typeof response.argument.callback == "function"){
12149             response.argument.callback(this.el, true, response);
12150         }
12151     },
12152
12153     /**
12154      * @private
12155      */
12156     processFailure : function(response){
12157         this.transaction = null;
12158         this.fireEvent("failure", this.el, response);
12159         if(typeof response.argument.callback == "function"){
12160             response.argument.callback(this.el, false, response);
12161         }
12162     },
12163
12164     /**
12165      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12166      * @param {Object} renderer The object implementing the render() method
12167      */
12168     setRenderer : function(renderer){
12169         this.renderer = renderer;
12170     },
12171
12172     getRenderer : function(){
12173        return this.renderer;
12174     },
12175
12176     /**
12177      * Set the defaultUrl used for updates
12178      * @param {String/Function} defaultUrl The url or a function to call to get the url
12179      */
12180     setDefaultUrl : function(defaultUrl){
12181         this.defaultUrl = defaultUrl;
12182     },
12183
12184     /**
12185      * Aborts the executing transaction
12186      */
12187     abort : function(){
12188         if(this.transaction){
12189             Roo.Ajax.abort(this.transaction);
12190         }
12191     },
12192
12193     /**
12194      * Returns true if an update is in progress
12195      * @return {Boolean}
12196      */
12197     isUpdating : function(){
12198         if(this.transaction){
12199             return Roo.Ajax.isLoading(this.transaction);
12200         }
12201         return false;
12202     }
12203 });
12204
12205 /**
12206  * @class Roo.UpdateManager.defaults
12207  * @static (not really - but it helps the doc tool)
12208  * The defaults collection enables customizing the default properties of UpdateManager
12209  */
12210    Roo.UpdateManager.defaults = {
12211        /**
12212          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12213          * @type Number
12214          */
12215          timeout : 30,
12216
12217          /**
12218          * True to process scripts by default (Defaults to false).
12219          * @type Boolean
12220          */
12221         loadScripts : false,
12222
12223         /**
12224         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12225         * @type String
12226         */
12227         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12228         /**
12229          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12230          * @type Boolean
12231          */
12232         disableCaching : false,
12233         /**
12234          * Whether to show indicatorText when loading (Defaults to true).
12235          * @type Boolean
12236          */
12237         showLoadIndicator : true,
12238         /**
12239          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12240          * @type String
12241          */
12242         indicatorText : '<div class="loading-indicator">Loading...</div>'
12243    };
12244
12245 /**
12246  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12247  *Usage:
12248  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12249  * @param {String/HTMLElement/Roo.Element} el The element to update
12250  * @param {String} url The url
12251  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12252  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12253  * @static
12254  * @deprecated
12255  * @member Roo.UpdateManager
12256  */
12257 Roo.UpdateManager.updateElement = function(el, url, params, options){
12258     var um = Roo.get(el, true).getUpdateManager();
12259     Roo.apply(um, options);
12260     um.update(url, params, options ? options.callback : null);
12261 };
12262 // alias for backwards compat
12263 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12264 /**
12265  * @class Roo.UpdateManager.BasicRenderer
12266  * Default Content renderer. Updates the elements innerHTML with the responseText.
12267  */
12268 Roo.UpdateManager.BasicRenderer = function(){};
12269
12270 Roo.UpdateManager.BasicRenderer.prototype = {
12271     /**
12272      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12273      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12274      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12275      * @param {Roo.Element} el The element being rendered
12276      * @param {Object} response The YUI Connect response object
12277      * @param {UpdateManager} updateManager The calling update manager
12278      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12279      */
12280      render : function(el, response, updateManager, callback){
12281         el.update(response.responseText, updateManager.loadScripts, callback);
12282     }
12283 };
12284 /*
12285  * Based on:
12286  * Roo JS
12287  * (c)) Alan Knowles
12288  * Licence : LGPL
12289  */
12290
12291
12292 /**
12293  * @class Roo.DomTemplate
12294  * @extends Roo.Template
12295  * An effort at a dom based template engine..
12296  *
12297  * Similar to XTemplate, except it uses dom parsing to create the template..
12298  *
12299  * Supported features:
12300  *
12301  *  Tags:
12302
12303 <pre><code>
12304       {a_variable} - output encoded.
12305       {a_variable.format:("Y-m-d")} - call a method on the variable
12306       {a_variable:raw} - unencoded output
12307       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12308       {a_variable:this.method_on_template(...)} - call a method on the template object.
12309  
12310 </code></pre>
12311  *  The tpl tag:
12312 <pre><code>
12313         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12314         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12315         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12316         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12317   
12318 </code></pre>
12319  *      
12320  */
12321 Roo.DomTemplate = function()
12322 {
12323      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12324      if (this.html) {
12325         this.compile();
12326      }
12327 };
12328
12329
12330 Roo.extend(Roo.DomTemplate, Roo.Template, {
12331     /**
12332      * id counter for sub templates.
12333      */
12334     id : 0,
12335     /**
12336      * flag to indicate if dom parser is inside a pre,
12337      * it will strip whitespace if not.
12338      */
12339     inPre : false,
12340     
12341     /**
12342      * The various sub templates
12343      */
12344     tpls : false,
12345     
12346     
12347     
12348     /**
12349      *
12350      * basic tag replacing syntax
12351      * WORD:WORD()
12352      *
12353      * // you can fake an object call by doing this
12354      *  x.t:(test,tesT) 
12355      * 
12356      */
12357     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12358     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12359     
12360     iterChild : function (node, method) {
12361         
12362         var oldPre = this.inPre;
12363         if (node.tagName == 'PRE') {
12364             this.inPre = true;
12365         }
12366         for( var i = 0; i < node.childNodes.length; i++) {
12367             method.call(this, node.childNodes[i]);
12368         }
12369         this.inPre = oldPre;
12370     },
12371     
12372     
12373     
12374     /**
12375      * compile the template
12376      *
12377      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12378      *
12379      */
12380     compile: function()
12381     {
12382         var s = this.html;
12383         
12384         // covert the html into DOM...
12385         var doc = false;
12386         var div =false;
12387         try {
12388             doc = document.implementation.createHTMLDocument("");
12389             doc.documentElement.innerHTML =   this.html  ;
12390             div = doc.documentElement;
12391         } catch (e) {
12392             // old IE... - nasty -- it causes all sorts of issues.. with
12393             // images getting pulled from server..
12394             div = document.createElement('div');
12395             div.innerHTML = this.html;
12396         }
12397         //doc.documentElement.innerHTML = htmlBody
12398          
12399         
12400         
12401         this.tpls = [];
12402         var _t = this;
12403         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12404         
12405         var tpls = this.tpls;
12406         
12407         // create a top level template from the snippet..
12408         
12409         //Roo.log(div.innerHTML);
12410         
12411         var tpl = {
12412             uid : 'master',
12413             id : this.id++,
12414             attr : false,
12415             value : false,
12416             body : div.innerHTML,
12417             
12418             forCall : false,
12419             execCall : false,
12420             dom : div,
12421             isTop : true
12422             
12423         };
12424         tpls.unshift(tpl);
12425         
12426         
12427         // compile them...
12428         this.tpls = [];
12429         Roo.each(tpls, function(tp){
12430             this.compileTpl(tp);
12431             this.tpls[tp.id] = tp;
12432         }, this);
12433         
12434         this.master = tpls[0];
12435         return this;
12436         
12437         
12438     },
12439     
12440     compileNode : function(node, istop) {
12441         // test for
12442         //Roo.log(node);
12443         
12444         
12445         // skip anything not a tag..
12446         if (node.nodeType != 1) {
12447             if (node.nodeType == 3 && !this.inPre) {
12448                 // reduce white space..
12449                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12450                 
12451             }
12452             return;
12453         }
12454         
12455         var tpl = {
12456             uid : false,
12457             id : false,
12458             attr : false,
12459             value : false,
12460             body : '',
12461             
12462             forCall : false,
12463             execCall : false,
12464             dom : false,
12465             isTop : istop
12466             
12467             
12468         };
12469         
12470         
12471         switch(true) {
12472             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12473             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12474             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12475             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12476             // no default..
12477         }
12478         
12479         
12480         if (!tpl.attr) {
12481             // just itterate children..
12482             this.iterChild(node,this.compileNode);
12483             return;
12484         }
12485         tpl.uid = this.id++;
12486         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12487         node.removeAttribute('roo-'+ tpl.attr);
12488         if (tpl.attr != 'name') {
12489             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12490             node.parentNode.replaceChild(placeholder,  node);
12491         } else {
12492             
12493             var placeholder =  document.createElement('span');
12494             placeholder.className = 'roo-tpl-' + tpl.value;
12495             node.parentNode.replaceChild(placeholder,  node);
12496         }
12497         
12498         // parent now sees '{domtplXXXX}
12499         this.iterChild(node,this.compileNode);
12500         
12501         // we should now have node body...
12502         var div = document.createElement('div');
12503         div.appendChild(node);
12504         tpl.dom = node;
12505         // this has the unfortunate side effect of converting tagged attributes
12506         // eg. href="{...}" into %7C...%7D
12507         // this has been fixed by searching for those combo's although it's a bit hacky..
12508         
12509         
12510         tpl.body = div.innerHTML;
12511         
12512         
12513          
12514         tpl.id = tpl.uid;
12515         switch(tpl.attr) {
12516             case 'for' :
12517                 switch (tpl.value) {
12518                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12519                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12520                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12521                 }
12522                 break;
12523             
12524             case 'exec':
12525                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12526                 break;
12527             
12528             case 'if':     
12529                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12530                 break;
12531             
12532             case 'name':
12533                 tpl.id  = tpl.value; // replace non characters???
12534                 break;
12535             
12536         }
12537         
12538         
12539         this.tpls.push(tpl);
12540         
12541         
12542         
12543     },
12544     
12545     
12546     
12547     
12548     /**
12549      * Compile a segment of the template into a 'sub-template'
12550      *
12551      * 
12552      * 
12553      *
12554      */
12555     compileTpl : function(tpl)
12556     {
12557         var fm = Roo.util.Format;
12558         var useF = this.disableFormats !== true;
12559         
12560         var sep = Roo.isGecko ? "+\n" : ",\n";
12561         
12562         var undef = function(str) {
12563             Roo.debug && Roo.log("Property not found :"  + str);
12564             return '';
12565         };
12566           
12567         //Roo.log(tpl.body);
12568         
12569         
12570         
12571         var fn = function(m, lbrace, name, format, args)
12572         {
12573             //Roo.log("ARGS");
12574             //Roo.log(arguments);
12575             args = args ? args.replace(/\\'/g,"'") : args;
12576             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12577             if (typeof(format) == 'undefined') {
12578                 format =  'htmlEncode'; 
12579             }
12580             if (format == 'raw' ) {
12581                 format = false;
12582             }
12583             
12584             if(name.substr(0, 6) == 'domtpl'){
12585                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12586             }
12587             
12588             // build an array of options to determine if value is undefined..
12589             
12590             // basically get 'xxxx.yyyy' then do
12591             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12592             //    (function () { Roo.log("Property not found"); return ''; })() :
12593             //    ......
12594             
12595             var udef_ar = [];
12596             var lookfor = '';
12597             Roo.each(name.split('.'), function(st) {
12598                 lookfor += (lookfor.length ? '.': '') + st;
12599                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12600             });
12601             
12602             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12603             
12604             
12605             if(format && useF){
12606                 
12607                 args = args ? ',' + args : "";
12608                  
12609                 if(format.substr(0, 5) != "this."){
12610                     format = "fm." + format + '(';
12611                 }else{
12612                     format = 'this.call("'+ format.substr(5) + '", ';
12613                     args = ", values";
12614                 }
12615                 
12616                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12617             }
12618              
12619             if (args && args.length) {
12620                 // called with xxyx.yuu:(test,test)
12621                 // change to ()
12622                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12623             }
12624             // raw.. - :raw modifier..
12625             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12626             
12627         };
12628         var body;
12629         // branched to use + in gecko and [].join() in others
12630         if(Roo.isGecko){
12631             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12632                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12633                     "';};};";
12634         }else{
12635             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12636             body.push(tpl.body.replace(/(\r\n|\n)/g,
12637                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12638             body.push("'].join('');};};");
12639             body = body.join('');
12640         }
12641         
12642         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12643        
12644         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12645         eval(body);
12646         
12647         return this;
12648     },
12649      
12650     /**
12651      * same as applyTemplate, except it's done to one of the subTemplates
12652      * when using named templates, you can do:
12653      *
12654      * var str = pl.applySubTemplate('your-name', values);
12655      *
12656      * 
12657      * @param {Number} id of the template
12658      * @param {Object} values to apply to template
12659      * @param {Object} parent (normaly the instance of this object)
12660      */
12661     applySubTemplate : function(id, values, parent)
12662     {
12663         
12664         
12665         var t = this.tpls[id];
12666         
12667         
12668         try { 
12669             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12670                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12671                 return '';
12672             }
12673         } catch(e) {
12674             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12675             Roo.log(values);
12676           
12677             return '';
12678         }
12679         try { 
12680             
12681             if(t.execCall && t.execCall.call(this, values, parent)){
12682                 return '';
12683             }
12684         } catch(e) {
12685             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12686             Roo.log(values);
12687             return '';
12688         }
12689         
12690         try {
12691             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12692             parent = t.target ? values : parent;
12693             if(t.forCall && vs instanceof Array){
12694                 var buf = [];
12695                 for(var i = 0, len = vs.length; i < len; i++){
12696                     try {
12697                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12698                     } catch (e) {
12699                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12700                         Roo.log(e.body);
12701                         //Roo.log(t.compiled);
12702                         Roo.log(vs[i]);
12703                     }   
12704                 }
12705                 return buf.join('');
12706             }
12707         } catch (e) {
12708             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12709             Roo.log(values);
12710             return '';
12711         }
12712         try {
12713             return t.compiled.call(this, vs, parent);
12714         } catch (e) {
12715             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12716             Roo.log(e.body);
12717             //Roo.log(t.compiled);
12718             Roo.log(values);
12719             return '';
12720         }
12721     },
12722
12723    
12724
12725     applyTemplate : function(values){
12726         return this.master.compiled.call(this, values, {});
12727         //var s = this.subs;
12728     },
12729
12730     apply : function(){
12731         return this.applyTemplate.apply(this, arguments);
12732     }
12733
12734  });
12735
12736 Roo.DomTemplate.from = function(el){
12737     el = Roo.getDom(el);
12738     return new Roo.Domtemplate(el.value || el.innerHTML);
12739 };/*
12740  * Based on:
12741  * Ext JS Library 1.1.1
12742  * Copyright(c) 2006-2007, Ext JS, LLC.
12743  *
12744  * Originally Released Under LGPL - original licence link has changed is not relivant.
12745  *
12746  * Fork - LGPL
12747  * <script type="text/javascript">
12748  */
12749
12750 /**
12751  * @class Roo.util.DelayedTask
12752  * Provides a convenient method of performing setTimeout where a new
12753  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12754  * You can use this class to buffer
12755  * the keypress events for a certain number of milliseconds, and perform only if they stop
12756  * for that amount of time.
12757  * @constructor The parameters to this constructor serve as defaults and are not required.
12758  * @param {Function} fn (optional) The default function to timeout
12759  * @param {Object} scope (optional) The default scope of that timeout
12760  * @param {Array} args (optional) The default Array of arguments
12761  */
12762 Roo.util.DelayedTask = function(fn, scope, args){
12763     var id = null, d, t;
12764
12765     var call = function(){
12766         var now = new Date().getTime();
12767         if(now - t >= d){
12768             clearInterval(id);
12769             id = null;
12770             fn.apply(scope, args || []);
12771         }
12772     };
12773     /**
12774      * Cancels any pending timeout and queues a new one
12775      * @param {Number} delay The milliseconds to delay
12776      * @param {Function} newFn (optional) Overrides function passed to constructor
12777      * @param {Object} newScope (optional) Overrides scope passed to constructor
12778      * @param {Array} newArgs (optional) Overrides args passed to constructor
12779      */
12780     this.delay = function(delay, newFn, newScope, newArgs){
12781         if(id && delay != d){
12782             this.cancel();
12783         }
12784         d = delay;
12785         t = new Date().getTime();
12786         fn = newFn || fn;
12787         scope = newScope || scope;
12788         args = newArgs || args;
12789         if(!id){
12790             id = setInterval(call, d);
12791         }
12792     };
12793
12794     /**
12795      * Cancel the last queued timeout
12796      */
12797     this.cancel = function(){
12798         if(id){
12799             clearInterval(id);
12800             id = null;
12801         }
12802     };
12803 };/*
12804  * Based on:
12805  * Ext JS Library 1.1.1
12806  * Copyright(c) 2006-2007, Ext JS, LLC.
12807  *
12808  * Originally Released Under LGPL - original licence link has changed is not relivant.
12809  *
12810  * Fork - LGPL
12811  * <script type="text/javascript">
12812  */
12813  
12814  
12815 Roo.util.TaskRunner = function(interval){
12816     interval = interval || 10;
12817     var tasks = [], removeQueue = [];
12818     var id = 0;
12819     var running = false;
12820
12821     var stopThread = function(){
12822         running = false;
12823         clearInterval(id);
12824         id = 0;
12825     };
12826
12827     var startThread = function(){
12828         if(!running){
12829             running = true;
12830             id = setInterval(runTasks, interval);
12831         }
12832     };
12833
12834     var removeTask = function(task){
12835         removeQueue.push(task);
12836         if(task.onStop){
12837             task.onStop();
12838         }
12839     };
12840
12841     var runTasks = function(){
12842         if(removeQueue.length > 0){
12843             for(var i = 0, len = removeQueue.length; i < len; i++){
12844                 tasks.remove(removeQueue[i]);
12845             }
12846             removeQueue = [];
12847             if(tasks.length < 1){
12848                 stopThread();
12849                 return;
12850             }
12851         }
12852         var now = new Date().getTime();
12853         for(var i = 0, len = tasks.length; i < len; ++i){
12854             var t = tasks[i];
12855             var itime = now - t.taskRunTime;
12856             if(t.interval <= itime){
12857                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12858                 t.taskRunTime = now;
12859                 if(rt === false || t.taskRunCount === t.repeat){
12860                     removeTask(t);
12861                     return;
12862                 }
12863             }
12864             if(t.duration && t.duration <= (now - t.taskStartTime)){
12865                 removeTask(t);
12866             }
12867         }
12868     };
12869
12870     /**
12871      * Queues a new task.
12872      * @param {Object} task
12873      */
12874     this.start = function(task){
12875         tasks.push(task);
12876         task.taskStartTime = new Date().getTime();
12877         task.taskRunTime = 0;
12878         task.taskRunCount = 0;
12879         startThread();
12880         return task;
12881     };
12882
12883     this.stop = function(task){
12884         removeTask(task);
12885         return task;
12886     };
12887
12888     this.stopAll = function(){
12889         stopThread();
12890         for(var i = 0, len = tasks.length; i < len; i++){
12891             if(tasks[i].onStop){
12892                 tasks[i].onStop();
12893             }
12894         }
12895         tasks = [];
12896         removeQueue = [];
12897     };
12898 };
12899
12900 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12901  * Based on:
12902  * Ext JS Library 1.1.1
12903  * Copyright(c) 2006-2007, Ext JS, LLC.
12904  *
12905  * Originally Released Under LGPL - original licence link has changed is not relivant.
12906  *
12907  * Fork - LGPL
12908  * <script type="text/javascript">
12909  */
12910
12911  
12912 /**
12913  * @class Roo.util.MixedCollection
12914  * @extends Roo.util.Observable
12915  * A Collection class that maintains both numeric indexes and keys and exposes events.
12916  * @constructor
12917  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12918  * collection (defaults to false)
12919  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12920  * and return the key value for that item.  This is used when available to look up the key on items that
12921  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12922  * equivalent to providing an implementation for the {@link #getKey} method.
12923  */
12924 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12925     this.items = [];
12926     this.map = {};
12927     this.keys = [];
12928     this.length = 0;
12929     this.addEvents({
12930         /**
12931          * @event clear
12932          * Fires when the collection is cleared.
12933          */
12934         "clear" : true,
12935         /**
12936          * @event add
12937          * Fires when an item is added to the collection.
12938          * @param {Number} index The index at which the item was added.
12939          * @param {Object} o The item added.
12940          * @param {String} key The key associated with the added item.
12941          */
12942         "add" : true,
12943         /**
12944          * @event replace
12945          * Fires when an item is replaced in the collection.
12946          * @param {String} key he key associated with the new added.
12947          * @param {Object} old The item being replaced.
12948          * @param {Object} new The new item.
12949          */
12950         "replace" : true,
12951         /**
12952          * @event remove
12953          * Fires when an item is removed from the collection.
12954          * @param {Object} o The item being removed.
12955          * @param {String} key (optional) The key associated with the removed item.
12956          */
12957         "remove" : true,
12958         "sort" : true
12959     });
12960     this.allowFunctions = allowFunctions === true;
12961     if(keyFn){
12962         this.getKey = keyFn;
12963     }
12964     Roo.util.MixedCollection.superclass.constructor.call(this);
12965 };
12966
12967 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12968     allowFunctions : false,
12969     
12970 /**
12971  * Adds an item to the collection.
12972  * @param {String} key The key to associate with the item
12973  * @param {Object} o The item to add.
12974  * @return {Object} The item added.
12975  */
12976     add : function(key, o){
12977         if(arguments.length == 1){
12978             o = arguments[0];
12979             key = this.getKey(o);
12980         }
12981         if(typeof key == "undefined" || key === null){
12982             this.length++;
12983             this.items.push(o);
12984             this.keys.push(null);
12985         }else{
12986             var old = this.map[key];
12987             if(old){
12988                 return this.replace(key, o);
12989             }
12990             this.length++;
12991             this.items.push(o);
12992             this.map[key] = o;
12993             this.keys.push(key);
12994         }
12995         this.fireEvent("add", this.length-1, o, key);
12996         return o;
12997     },
12998        
12999 /**
13000   * MixedCollection has a generic way to fetch keys if you implement getKey.
13001 <pre><code>
13002 // normal way
13003 var mc = new Roo.util.MixedCollection();
13004 mc.add(someEl.dom.id, someEl);
13005 mc.add(otherEl.dom.id, otherEl);
13006 //and so on
13007
13008 // using getKey
13009 var mc = new Roo.util.MixedCollection();
13010 mc.getKey = function(el){
13011    return el.dom.id;
13012 };
13013 mc.add(someEl);
13014 mc.add(otherEl);
13015
13016 // or via the constructor
13017 var mc = new Roo.util.MixedCollection(false, function(el){
13018    return el.dom.id;
13019 });
13020 mc.add(someEl);
13021 mc.add(otherEl);
13022 </code></pre>
13023  * @param o {Object} The item for which to find the key.
13024  * @return {Object} The key for the passed item.
13025  */
13026     getKey : function(o){
13027          return o.id; 
13028     },
13029    
13030 /**
13031  * Replaces an item in the collection.
13032  * @param {String} key The key associated with the item to replace, or the item to replace.
13033  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13034  * @return {Object}  The new item.
13035  */
13036     replace : function(key, o){
13037         if(arguments.length == 1){
13038             o = arguments[0];
13039             key = this.getKey(o);
13040         }
13041         var old = this.item(key);
13042         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13043              return this.add(key, o);
13044         }
13045         var index = this.indexOfKey(key);
13046         this.items[index] = o;
13047         this.map[key] = o;
13048         this.fireEvent("replace", key, old, o);
13049         return o;
13050     },
13051    
13052 /**
13053  * Adds all elements of an Array or an Object to the collection.
13054  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13055  * an Array of values, each of which are added to the collection.
13056  */
13057     addAll : function(objs){
13058         if(arguments.length > 1 || objs instanceof Array){
13059             var args = arguments.length > 1 ? arguments : objs;
13060             for(var i = 0, len = args.length; i < len; i++){
13061                 this.add(args[i]);
13062             }
13063         }else{
13064             for(var key in objs){
13065                 if(this.allowFunctions || typeof objs[key] != "function"){
13066                     this.add(key, objs[key]);
13067                 }
13068             }
13069         }
13070     },
13071    
13072 /**
13073  * Executes the specified function once for every item in the collection, passing each
13074  * item as the first and only parameter. returning false from the function will stop the iteration.
13075  * @param {Function} fn The function to execute for each item.
13076  * @param {Object} scope (optional) The scope in which to execute the function.
13077  */
13078     each : function(fn, scope){
13079         var items = [].concat(this.items); // each safe for removal
13080         for(var i = 0, len = items.length; i < len; i++){
13081             if(fn.call(scope || items[i], items[i], i, len) === false){
13082                 break;
13083             }
13084         }
13085     },
13086    
13087 /**
13088  * Executes the specified function once for every key in the collection, passing each
13089  * key, and its associated item as the first two parameters.
13090  * @param {Function} fn The function to execute for each item.
13091  * @param {Object} scope (optional) The scope in which to execute the function.
13092  */
13093     eachKey : function(fn, scope){
13094         for(var i = 0, len = this.keys.length; i < len; i++){
13095             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13096         }
13097     },
13098    
13099 /**
13100  * Returns the first item in the collection which elicits a true return value from the
13101  * passed selection function.
13102  * @param {Function} fn The selection function to execute for each item.
13103  * @param {Object} scope (optional) The scope in which to execute the function.
13104  * @return {Object} The first item in the collection which returned true from the selection function.
13105  */
13106     find : function(fn, scope){
13107         for(var i = 0, len = this.items.length; i < len; i++){
13108             if(fn.call(scope || window, this.items[i], this.keys[i])){
13109                 return this.items[i];
13110             }
13111         }
13112         return null;
13113     },
13114    
13115 /**
13116  * Inserts an item at the specified index in the collection.
13117  * @param {Number} index The index to insert the item at.
13118  * @param {String} key The key to associate with the new item, or the item itself.
13119  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13120  * @return {Object} The item inserted.
13121  */
13122     insert : function(index, key, o){
13123         if(arguments.length == 2){
13124             o = arguments[1];
13125             key = this.getKey(o);
13126         }
13127         if(index >= this.length){
13128             return this.add(key, o);
13129         }
13130         this.length++;
13131         this.items.splice(index, 0, o);
13132         if(typeof key != "undefined" && key != null){
13133             this.map[key] = o;
13134         }
13135         this.keys.splice(index, 0, key);
13136         this.fireEvent("add", index, o, key);
13137         return o;
13138     },
13139    
13140 /**
13141  * Removed an item from the collection.
13142  * @param {Object} o The item to remove.
13143  * @return {Object} The item removed.
13144  */
13145     remove : function(o){
13146         return this.removeAt(this.indexOf(o));
13147     },
13148    
13149 /**
13150  * Remove an item from a specified index in the collection.
13151  * @param {Number} index The index within the collection of the item to remove.
13152  */
13153     removeAt : function(index){
13154         if(index < this.length && index >= 0){
13155             this.length--;
13156             var o = this.items[index];
13157             this.items.splice(index, 1);
13158             var key = this.keys[index];
13159             if(typeof key != "undefined"){
13160                 delete this.map[key];
13161             }
13162             this.keys.splice(index, 1);
13163             this.fireEvent("remove", o, key);
13164         }
13165     },
13166    
13167 /**
13168  * Removed an item associated with the passed key fom the collection.
13169  * @param {String} key The key of the item to remove.
13170  */
13171     removeKey : function(key){
13172         return this.removeAt(this.indexOfKey(key));
13173     },
13174    
13175 /**
13176  * Returns the number of items in the collection.
13177  * @return {Number} the number of items in the collection.
13178  */
13179     getCount : function(){
13180         return this.length; 
13181     },
13182    
13183 /**
13184  * Returns index within the collection of the passed Object.
13185  * @param {Object} o The item to find the index of.
13186  * @return {Number} index of the item.
13187  */
13188     indexOf : function(o){
13189         if(!this.items.indexOf){
13190             for(var i = 0, len = this.items.length; i < len; i++){
13191                 if(this.items[i] == o) {
13192                     return i;
13193                 }
13194             }
13195             return -1;
13196         }else{
13197             return this.items.indexOf(o);
13198         }
13199     },
13200    
13201 /**
13202  * Returns index within the collection of the passed key.
13203  * @param {String} key The key to find the index of.
13204  * @return {Number} index of the key.
13205  */
13206     indexOfKey : function(key){
13207         if(!this.keys.indexOf){
13208             for(var i = 0, len = this.keys.length; i < len; i++){
13209                 if(this.keys[i] == key) {
13210                     return i;
13211                 }
13212             }
13213             return -1;
13214         }else{
13215             return this.keys.indexOf(key);
13216         }
13217     },
13218    
13219 /**
13220  * Returns the item associated with the passed key OR index. Key has priority over index.
13221  * @param {String/Number} key The key or index of the item.
13222  * @return {Object} The item associated with the passed key.
13223  */
13224     item : function(key){
13225         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13226         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13227     },
13228     
13229 /**
13230  * Returns the item at the specified index.
13231  * @param {Number} index The index of the item.
13232  * @return {Object}
13233  */
13234     itemAt : function(index){
13235         return this.items[index];
13236     },
13237     
13238 /**
13239  * Returns the item associated with the passed key.
13240  * @param {String/Number} key The key of the item.
13241  * @return {Object} The item associated with the passed key.
13242  */
13243     key : function(key){
13244         return this.map[key];
13245     },
13246    
13247 /**
13248  * Returns true if the collection contains the passed Object as an item.
13249  * @param {Object} o  The Object to look for in the collection.
13250  * @return {Boolean} True if the collection contains the Object as an item.
13251  */
13252     contains : function(o){
13253         return this.indexOf(o) != -1;
13254     },
13255    
13256 /**
13257  * Returns true if the collection contains the passed Object as a key.
13258  * @param {String} key The key to look for in the collection.
13259  * @return {Boolean} True if the collection contains the Object as a key.
13260  */
13261     containsKey : function(key){
13262         return typeof this.map[key] != "undefined";
13263     },
13264    
13265 /**
13266  * Removes all items from the collection.
13267  */
13268     clear : function(){
13269         this.length = 0;
13270         this.items = [];
13271         this.keys = [];
13272         this.map = {};
13273         this.fireEvent("clear");
13274     },
13275    
13276 /**
13277  * Returns the first item in the collection.
13278  * @return {Object} the first item in the collection..
13279  */
13280     first : function(){
13281         return this.items[0]; 
13282     },
13283    
13284 /**
13285  * Returns the last item in the collection.
13286  * @return {Object} the last item in the collection..
13287  */
13288     last : function(){
13289         return this.items[this.length-1];   
13290     },
13291     
13292     _sort : function(property, dir, fn){
13293         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13294         fn = fn || function(a, b){
13295             return a-b;
13296         };
13297         var c = [], k = this.keys, items = this.items;
13298         for(var i = 0, len = items.length; i < len; i++){
13299             c[c.length] = {key: k[i], value: items[i], index: i};
13300         }
13301         c.sort(function(a, b){
13302             var v = fn(a[property], b[property]) * dsc;
13303             if(v == 0){
13304                 v = (a.index < b.index ? -1 : 1);
13305             }
13306             return v;
13307         });
13308         for(var i = 0, len = c.length; i < len; i++){
13309             items[i] = c[i].value;
13310             k[i] = c[i].key;
13311         }
13312         this.fireEvent("sort", this);
13313     },
13314     
13315     /**
13316      * Sorts this collection with the passed comparison function
13317      * @param {String} direction (optional) "ASC" or "DESC"
13318      * @param {Function} fn (optional) comparison function
13319      */
13320     sort : function(dir, fn){
13321         this._sort("value", dir, fn);
13322     },
13323     
13324     /**
13325      * Sorts this collection by keys
13326      * @param {String} direction (optional) "ASC" or "DESC"
13327      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13328      */
13329     keySort : function(dir, fn){
13330         this._sort("key", dir, fn || function(a, b){
13331             return String(a).toUpperCase()-String(b).toUpperCase();
13332         });
13333     },
13334     
13335     /**
13336      * Returns a range of items in this collection
13337      * @param {Number} startIndex (optional) defaults to 0
13338      * @param {Number} endIndex (optional) default to the last item
13339      * @return {Array} An array of items
13340      */
13341     getRange : function(start, end){
13342         var items = this.items;
13343         if(items.length < 1){
13344             return [];
13345         }
13346         start = start || 0;
13347         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13348         var r = [];
13349         if(start <= end){
13350             for(var i = start; i <= end; i++) {
13351                     r[r.length] = items[i];
13352             }
13353         }else{
13354             for(var i = start; i >= end; i--) {
13355                     r[r.length] = items[i];
13356             }
13357         }
13358         return r;
13359     },
13360         
13361     /**
13362      * Filter the <i>objects</i> in this collection by a specific property. 
13363      * Returns a new collection that has been filtered.
13364      * @param {String} property A property on your objects
13365      * @param {String/RegExp} value Either string that the property values 
13366      * should start with or a RegExp to test against the property
13367      * @return {MixedCollection} The new filtered collection
13368      */
13369     filter : function(property, value){
13370         if(!value.exec){ // not a regex
13371             value = String(value);
13372             if(value.length == 0){
13373                 return this.clone();
13374             }
13375             value = new RegExp("^" + Roo.escapeRe(value), "i");
13376         }
13377         return this.filterBy(function(o){
13378             return o && value.test(o[property]);
13379         });
13380         },
13381     
13382     /**
13383      * Filter by a function. * Returns a new collection that has been filtered.
13384      * The passed function will be called with each 
13385      * object in the collection. If the function returns true, the value is included 
13386      * otherwise it is filtered.
13387      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13388      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13389      * @return {MixedCollection} The new filtered collection
13390      */
13391     filterBy : function(fn, scope){
13392         var r = new Roo.util.MixedCollection();
13393         r.getKey = this.getKey;
13394         var k = this.keys, it = this.items;
13395         for(var i = 0, len = it.length; i < len; i++){
13396             if(fn.call(scope||this, it[i], k[i])){
13397                                 r.add(k[i], it[i]);
13398                         }
13399         }
13400         return r;
13401     },
13402     
13403     /**
13404      * Creates a duplicate of this collection
13405      * @return {MixedCollection}
13406      */
13407     clone : function(){
13408         var r = new Roo.util.MixedCollection();
13409         var k = this.keys, it = this.items;
13410         for(var i = 0, len = it.length; i < len; i++){
13411             r.add(k[i], it[i]);
13412         }
13413         r.getKey = this.getKey;
13414         return r;
13415     }
13416 });
13417 /**
13418  * Returns the item associated with the passed key or index.
13419  * @method
13420  * @param {String/Number} key The key or index of the item.
13421  * @return {Object} The item associated with the passed key.
13422  */
13423 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13424  * Based on:
13425  * Ext JS Library 1.1.1
13426  * Copyright(c) 2006-2007, Ext JS, LLC.
13427  *
13428  * Originally Released Under LGPL - original licence link has changed is not relivant.
13429  *
13430  * Fork - LGPL
13431  * <script type="text/javascript">
13432  */
13433 /**
13434  * @class Roo.util.JSON
13435  * Modified version of Douglas Crockford"s json.js that doesn"t
13436  * mess with the Object prototype 
13437  * http://www.json.org/js.html
13438  * @singleton
13439  */
13440 Roo.util.JSON = new (function(){
13441     var useHasOwn = {}.hasOwnProperty ? true : false;
13442     
13443     // crashes Safari in some instances
13444     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13445     
13446     var pad = function(n) {
13447         return n < 10 ? "0" + n : n;
13448     };
13449     
13450     var m = {
13451         "\b": '\\b',
13452         "\t": '\\t',
13453         "\n": '\\n',
13454         "\f": '\\f',
13455         "\r": '\\r',
13456         '"' : '\\"',
13457         "\\": '\\\\'
13458     };
13459
13460     var encodeString = function(s){
13461         if (/["\\\x00-\x1f]/.test(s)) {
13462             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13463                 var c = m[b];
13464                 if(c){
13465                     return c;
13466                 }
13467                 c = b.charCodeAt();
13468                 return "\\u00" +
13469                     Math.floor(c / 16).toString(16) +
13470                     (c % 16).toString(16);
13471             }) + '"';
13472         }
13473         return '"' + s + '"';
13474     };
13475     
13476     var encodeArray = function(o){
13477         var a = ["["], b, i, l = o.length, v;
13478             for (i = 0; i < l; i += 1) {
13479                 v = o[i];
13480                 switch (typeof v) {
13481                     case "undefined":
13482                     case "function":
13483                     case "unknown":
13484                         break;
13485                     default:
13486                         if (b) {
13487                             a.push(',');
13488                         }
13489                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13490                         b = true;
13491                 }
13492             }
13493             a.push("]");
13494             return a.join("");
13495     };
13496     
13497     var encodeDate = function(o){
13498         return '"' + o.getFullYear() + "-" +
13499                 pad(o.getMonth() + 1) + "-" +
13500                 pad(o.getDate()) + "T" +
13501                 pad(o.getHours()) + ":" +
13502                 pad(o.getMinutes()) + ":" +
13503                 pad(o.getSeconds()) + '"';
13504     };
13505     
13506     /**
13507      * Encodes an Object, Array or other value
13508      * @param {Mixed} o The variable to encode
13509      * @return {String} The JSON string
13510      */
13511     this.encode = function(o)
13512     {
13513         // should this be extended to fully wrap stringify..
13514         
13515         if(typeof o == "undefined" || o === null){
13516             return "null";
13517         }else if(o instanceof Array){
13518             return encodeArray(o);
13519         }else if(o instanceof Date){
13520             return encodeDate(o);
13521         }else if(typeof o == "string"){
13522             return encodeString(o);
13523         }else if(typeof o == "number"){
13524             return isFinite(o) ? String(o) : "null";
13525         }else if(typeof o == "boolean"){
13526             return String(o);
13527         }else {
13528             var a = ["{"], b, i, v;
13529             for (i in o) {
13530                 if(!useHasOwn || o.hasOwnProperty(i)) {
13531                     v = o[i];
13532                     switch (typeof v) {
13533                     case "undefined":
13534                     case "function":
13535                     case "unknown":
13536                         break;
13537                     default:
13538                         if(b){
13539                             a.push(',');
13540                         }
13541                         a.push(this.encode(i), ":",
13542                                 v === null ? "null" : this.encode(v));
13543                         b = true;
13544                     }
13545                 }
13546             }
13547             a.push("}");
13548             return a.join("");
13549         }
13550     };
13551     
13552     /**
13553      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13554      * @param {String} json The JSON string
13555      * @return {Object} The resulting object
13556      */
13557     this.decode = function(json){
13558         
13559         return  /** eval:var:json */ eval("(" + json + ')');
13560     };
13561 })();
13562 /** 
13563  * Shorthand for {@link Roo.util.JSON#encode}
13564  * @member Roo encode 
13565  * @method */
13566 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13567 /** 
13568  * Shorthand for {@link Roo.util.JSON#decode}
13569  * @member Roo decode 
13570  * @method */
13571 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13572 /*
13573  * Based on:
13574  * Ext JS Library 1.1.1
13575  * Copyright(c) 2006-2007, Ext JS, LLC.
13576  *
13577  * Originally Released Under LGPL - original licence link has changed is not relivant.
13578  *
13579  * Fork - LGPL
13580  * <script type="text/javascript">
13581  */
13582  
13583 /**
13584  * @class Roo.util.Format
13585  * Reusable data formatting functions
13586  * @singleton
13587  */
13588 Roo.util.Format = function(){
13589     var trimRe = /^\s+|\s+$/g;
13590     return {
13591         /**
13592          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13593          * @param {String} value The string to truncate
13594          * @param {Number} length The maximum length to allow before truncating
13595          * @return {String} The converted text
13596          */
13597         ellipsis : function(value, len){
13598             if(value && value.length > len){
13599                 return value.substr(0, len-3)+"...";
13600             }
13601             return value;
13602         },
13603
13604         /**
13605          * Checks a reference and converts it to empty string if it is undefined
13606          * @param {Mixed} value Reference to check
13607          * @return {Mixed} Empty string if converted, otherwise the original value
13608          */
13609         undef : function(value){
13610             return typeof value != "undefined" ? value : "";
13611         },
13612
13613         /**
13614          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13615          * @param {String} value The string to encode
13616          * @return {String} The encoded text
13617          */
13618         htmlEncode : function(value){
13619             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13620         },
13621
13622         /**
13623          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13624          * @param {String} value The string to decode
13625          * @return {String} The decoded text
13626          */
13627         htmlDecode : function(value){
13628             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13629         },
13630
13631         /**
13632          * Trims any whitespace from either side of a string
13633          * @param {String} value The text to trim
13634          * @return {String} The trimmed text
13635          */
13636         trim : function(value){
13637             return String(value).replace(trimRe, "");
13638         },
13639
13640         /**
13641          * Returns a substring from within an original string
13642          * @param {String} value The original text
13643          * @param {Number} start The start index of the substring
13644          * @param {Number} length The length of the substring
13645          * @return {String} The substring
13646          */
13647         substr : function(value, start, length){
13648             return String(value).substr(start, length);
13649         },
13650
13651         /**
13652          * Converts a string to all lower case letters
13653          * @param {String} value The text to convert
13654          * @return {String} The converted text
13655          */
13656         lowercase : function(value){
13657             return String(value).toLowerCase();
13658         },
13659
13660         /**
13661          * Converts a string to all upper case letters
13662          * @param {String} value The text to convert
13663          * @return {String} The converted text
13664          */
13665         uppercase : function(value){
13666             return String(value).toUpperCase();
13667         },
13668
13669         /**
13670          * Converts the first character only of a string to upper case
13671          * @param {String} value The text to convert
13672          * @return {String} The converted text
13673          */
13674         capitalize : function(value){
13675             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13676         },
13677
13678         // private
13679         call : function(value, fn){
13680             if(arguments.length > 2){
13681                 var args = Array.prototype.slice.call(arguments, 2);
13682                 args.unshift(value);
13683                  
13684                 return /** eval:var:value */  eval(fn).apply(window, args);
13685             }else{
13686                 /** eval:var:value */
13687                 return /** eval:var:value */ eval(fn).call(window, value);
13688             }
13689         },
13690
13691        
13692         /**
13693          * safer version of Math.toFixed..??/
13694          * @param {Number/String} value The numeric value to format
13695          * @param {Number/String} value Decimal places 
13696          * @return {String} The formatted currency string
13697          */
13698         toFixed : function(v, n)
13699         {
13700             // why not use to fixed - precision is buggered???
13701             if (!n) {
13702                 return Math.round(v-0);
13703             }
13704             var fact = Math.pow(10,n+1);
13705             v = (Math.round((v-0)*fact))/fact;
13706             var z = (''+fact).substring(2);
13707             if (v == Math.floor(v)) {
13708                 return Math.floor(v) + '.' + z;
13709             }
13710             
13711             // now just padd decimals..
13712             var ps = String(v).split('.');
13713             var fd = (ps[1] + z);
13714             var r = fd.substring(0,n); 
13715             var rm = fd.substring(n); 
13716             if (rm < 5) {
13717                 return ps[0] + '.' + r;
13718             }
13719             r*=1; // turn it into a number;
13720             r++;
13721             if (String(r).length != n) {
13722                 ps[0]*=1;
13723                 ps[0]++;
13724                 r = String(r).substring(1); // chop the end off.
13725             }
13726             
13727             return ps[0] + '.' + r;
13728              
13729         },
13730         
13731         /**
13732          * Format a number as US currency
13733          * @param {Number/String} value The numeric value to format
13734          * @return {String} The formatted currency string
13735          */
13736         usMoney : function(v){
13737             return '$' + Roo.util.Format.number(v);
13738         },
13739         
13740         /**
13741          * Format a number
13742          * eventually this should probably emulate php's number_format
13743          * @param {Number/String} value The numeric value to format
13744          * @param {Number} decimals number of decimal places
13745          * @return {String} The formatted currency string
13746          */
13747         number : function(v,decimals)
13748         {
13749             // multiply and round.
13750             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13751             var mul = Math.pow(10, decimals);
13752             var zero = String(mul).substring(1);
13753             v = (Math.round((v-0)*mul))/mul;
13754             
13755             // if it's '0' number.. then
13756             
13757             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13758             v = String(v);
13759             var ps = v.split('.');
13760             var whole = ps[0];
13761             
13762             
13763             var r = /(\d+)(\d{3})/;
13764             // add comma's
13765             while (r.test(whole)) {
13766                 whole = whole.replace(r, '$1' + ',' + '$2');
13767             }
13768             
13769             
13770             var sub = ps[1] ?
13771                     // has decimals..
13772                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13773                     // does not have decimals
13774                     (decimals ? ('.' + zero) : '');
13775             
13776             
13777             return whole + sub ;
13778         },
13779         
13780         /**
13781          * Parse a value into a formatted date using the specified format pattern.
13782          * @param {Mixed} value The value to format
13783          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13784          * @return {String} The formatted date string
13785          */
13786         date : function(v, format){
13787             if(!v){
13788                 return "";
13789             }
13790             if(!(v instanceof Date)){
13791                 v = new Date(Date.parse(v));
13792             }
13793             return v.dateFormat(format || Roo.util.Format.defaults.date);
13794         },
13795
13796         /**
13797          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13798          * @param {String} format Any valid date format string
13799          * @return {Function} The date formatting function
13800          */
13801         dateRenderer : function(format){
13802             return function(v){
13803                 return Roo.util.Format.date(v, format);  
13804             };
13805         },
13806
13807         // private
13808         stripTagsRE : /<\/?[^>]+>/gi,
13809         
13810         /**
13811          * Strips all HTML tags
13812          * @param {Mixed} value The text from which to strip tags
13813          * @return {String} The stripped text
13814          */
13815         stripTags : function(v){
13816             return !v ? v : String(v).replace(this.stripTagsRE, "");
13817         }
13818     };
13819 }();
13820 Roo.util.Format.defaults = {
13821     date : 'd/M/Y'
13822 };/*
13823  * Based on:
13824  * Ext JS Library 1.1.1
13825  * Copyright(c) 2006-2007, Ext JS, LLC.
13826  *
13827  * Originally Released Under LGPL - original licence link has changed is not relivant.
13828  *
13829  * Fork - LGPL
13830  * <script type="text/javascript">
13831  */
13832
13833
13834  
13835
13836 /**
13837  * @class Roo.MasterTemplate
13838  * @extends Roo.Template
13839  * Provides a template that can have child templates. The syntax is:
13840 <pre><code>
13841 var t = new Roo.MasterTemplate(
13842         '&lt;select name="{name}"&gt;',
13843                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13844         '&lt;/select&gt;'
13845 );
13846 t.add('options', {value: 'foo', text: 'bar'});
13847 // or you can add multiple child elements in one shot
13848 t.addAll('options', [
13849     {value: 'foo', text: 'bar'},
13850     {value: 'foo2', text: 'bar2'},
13851     {value: 'foo3', text: 'bar3'}
13852 ]);
13853 // then append, applying the master template values
13854 t.append('my-form', {name: 'my-select'});
13855 </code></pre>
13856 * A name attribute for the child template is not required if you have only one child
13857 * template or you want to refer to them by index.
13858  */
13859 Roo.MasterTemplate = function(){
13860     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13861     this.originalHtml = this.html;
13862     var st = {};
13863     var m, re = this.subTemplateRe;
13864     re.lastIndex = 0;
13865     var subIndex = 0;
13866     while(m = re.exec(this.html)){
13867         var name = m[1], content = m[2];
13868         st[subIndex] = {
13869             name: name,
13870             index: subIndex,
13871             buffer: [],
13872             tpl : new Roo.Template(content)
13873         };
13874         if(name){
13875             st[name] = st[subIndex];
13876         }
13877         st[subIndex].tpl.compile();
13878         st[subIndex].tpl.call = this.call.createDelegate(this);
13879         subIndex++;
13880     }
13881     this.subCount = subIndex;
13882     this.subs = st;
13883 };
13884 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13885     /**
13886     * The regular expression used to match sub templates
13887     * @type RegExp
13888     * @property
13889     */
13890     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13891
13892     /**
13893      * Applies the passed values to a child template.
13894      * @param {String/Number} name (optional) The name or index of the child template
13895      * @param {Array/Object} values The values to be applied to the template
13896      * @return {MasterTemplate} this
13897      */
13898      add : function(name, values){
13899         if(arguments.length == 1){
13900             values = arguments[0];
13901             name = 0;
13902         }
13903         var s = this.subs[name];
13904         s.buffer[s.buffer.length] = s.tpl.apply(values);
13905         return this;
13906     },
13907
13908     /**
13909      * Applies all the passed values to a child template.
13910      * @param {String/Number} name (optional) The name or index of the child template
13911      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13912      * @param {Boolean} reset (optional) True to reset the template first
13913      * @return {MasterTemplate} this
13914      */
13915     fill : function(name, values, reset){
13916         var a = arguments;
13917         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13918             values = a[0];
13919             name = 0;
13920             reset = a[1];
13921         }
13922         if(reset){
13923             this.reset();
13924         }
13925         for(var i = 0, len = values.length; i < len; i++){
13926             this.add(name, values[i]);
13927         }
13928         return this;
13929     },
13930
13931     /**
13932      * Resets the template for reuse
13933      * @return {MasterTemplate} this
13934      */
13935      reset : function(){
13936         var s = this.subs;
13937         for(var i = 0; i < this.subCount; i++){
13938             s[i].buffer = [];
13939         }
13940         return this;
13941     },
13942
13943     applyTemplate : function(values){
13944         var s = this.subs;
13945         var replaceIndex = -1;
13946         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13947             return s[++replaceIndex].buffer.join("");
13948         });
13949         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13950     },
13951
13952     apply : function(){
13953         return this.applyTemplate.apply(this, arguments);
13954     },
13955
13956     compile : function(){return this;}
13957 });
13958
13959 /**
13960  * Alias for fill().
13961  * @method
13962  */
13963 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13964  /**
13965  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13966  * var tpl = Roo.MasterTemplate.from('element-id');
13967  * @param {String/HTMLElement} el
13968  * @param {Object} config
13969  * @static
13970  */
13971 Roo.MasterTemplate.from = function(el, config){
13972     el = Roo.getDom(el);
13973     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13974 };/*
13975  * Based on:
13976  * Ext JS Library 1.1.1
13977  * Copyright(c) 2006-2007, Ext JS, LLC.
13978  *
13979  * Originally Released Under LGPL - original licence link has changed is not relivant.
13980  *
13981  * Fork - LGPL
13982  * <script type="text/javascript">
13983  */
13984
13985  
13986 /**
13987  * @class Roo.util.CSS
13988  * Utility class for manipulating CSS rules
13989  * @singleton
13990  */
13991 Roo.util.CSS = function(){
13992         var rules = null;
13993         var doc = document;
13994
13995     var camelRe = /(-[a-z])/gi;
13996     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13997
13998    return {
13999    /**
14000     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14001     * tag and appended to the HEAD of the document.
14002     * @param {String|Object} cssText The text containing the css rules
14003     * @param {String} id An id to add to the stylesheet for later removal
14004     * @return {StyleSheet}
14005     */
14006     createStyleSheet : function(cssText, id){
14007         var ss;
14008         var head = doc.getElementsByTagName("head")[0];
14009         var nrules = doc.createElement("style");
14010         nrules.setAttribute("type", "text/css");
14011         if(id){
14012             nrules.setAttribute("id", id);
14013         }
14014         if (typeof(cssText) != 'string') {
14015             // support object maps..
14016             // not sure if this a good idea.. 
14017             // perhaps it should be merged with the general css handling
14018             // and handle js style props.
14019             var cssTextNew = [];
14020             for(var n in cssText) {
14021                 var citems = [];
14022                 for(var k in cssText[n]) {
14023                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14024                 }
14025                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14026                 
14027             }
14028             cssText = cssTextNew.join("\n");
14029             
14030         }
14031        
14032        
14033        if(Roo.isIE){
14034            head.appendChild(nrules);
14035            ss = nrules.styleSheet;
14036            ss.cssText = cssText;
14037        }else{
14038            try{
14039                 nrules.appendChild(doc.createTextNode(cssText));
14040            }catch(e){
14041                nrules.cssText = cssText; 
14042            }
14043            head.appendChild(nrules);
14044            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14045        }
14046        this.cacheStyleSheet(ss);
14047        return ss;
14048    },
14049
14050    /**
14051     * Removes a style or link tag by id
14052     * @param {String} id The id of the tag
14053     */
14054    removeStyleSheet : function(id){
14055        var existing = doc.getElementById(id);
14056        if(existing){
14057            existing.parentNode.removeChild(existing);
14058        }
14059    },
14060
14061    /**
14062     * Dynamically swaps an existing stylesheet reference for a new one
14063     * @param {String} id The id of an existing link tag to remove
14064     * @param {String} url The href of the new stylesheet to include
14065     */
14066    swapStyleSheet : function(id, url){
14067        this.removeStyleSheet(id);
14068        var ss = doc.createElement("link");
14069        ss.setAttribute("rel", "stylesheet");
14070        ss.setAttribute("type", "text/css");
14071        ss.setAttribute("id", id);
14072        ss.setAttribute("href", url);
14073        doc.getElementsByTagName("head")[0].appendChild(ss);
14074    },
14075    
14076    /**
14077     * Refresh the rule cache if you have dynamically added stylesheets
14078     * @return {Object} An object (hash) of rules indexed by selector
14079     */
14080    refreshCache : function(){
14081        return this.getRules(true);
14082    },
14083
14084    // private
14085    cacheStyleSheet : function(stylesheet){
14086        if(!rules){
14087            rules = {};
14088        }
14089        try{// try catch for cross domain access issue
14090            var ssRules = stylesheet.cssRules || stylesheet.rules;
14091            for(var j = ssRules.length-1; j >= 0; --j){
14092                rules[ssRules[j].selectorText] = ssRules[j];
14093            }
14094        }catch(e){}
14095    },
14096    
14097    /**
14098     * Gets all css rules for the document
14099     * @param {Boolean} refreshCache true to refresh the internal cache
14100     * @return {Object} An object (hash) of rules indexed by selector
14101     */
14102    getRules : function(refreshCache){
14103                 if(rules == null || refreshCache){
14104                         rules = {};
14105                         var ds = doc.styleSheets;
14106                         for(var i =0, len = ds.length; i < len; i++){
14107                             try{
14108                         this.cacheStyleSheet(ds[i]);
14109                     }catch(e){} 
14110                 }
14111                 }
14112                 return rules;
14113         },
14114         
14115         /**
14116     * Gets an an individual CSS rule by selector(s)
14117     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14118     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14119     * @return {CSSRule} The CSS rule or null if one is not found
14120     */
14121    getRule : function(selector, refreshCache){
14122                 var rs = this.getRules(refreshCache);
14123                 if(!(selector instanceof Array)){
14124                     return rs[selector];
14125                 }
14126                 for(var i = 0; i < selector.length; i++){
14127                         if(rs[selector[i]]){
14128                                 return rs[selector[i]];
14129                         }
14130                 }
14131                 return null;
14132         },
14133         
14134         
14135         /**
14136     * Updates a rule property
14137     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14138     * @param {String} property The css property
14139     * @param {String} value The new value for the property
14140     * @return {Boolean} true If a rule was found and updated
14141     */
14142    updateRule : function(selector, property, value){
14143                 if(!(selector instanceof Array)){
14144                         var rule = this.getRule(selector);
14145                         if(rule){
14146                                 rule.style[property.replace(camelRe, camelFn)] = value;
14147                                 return true;
14148                         }
14149                 }else{
14150                         for(var i = 0; i < selector.length; i++){
14151                                 if(this.updateRule(selector[i], property, value)){
14152                                         return true;
14153                                 }
14154                         }
14155                 }
14156                 return false;
14157         }
14158    };   
14159 }();/*
14160  * Based on:
14161  * Ext JS Library 1.1.1
14162  * Copyright(c) 2006-2007, Ext JS, LLC.
14163  *
14164  * Originally Released Under LGPL - original licence link has changed is not relivant.
14165  *
14166  * Fork - LGPL
14167  * <script type="text/javascript">
14168  */
14169
14170  
14171
14172 /**
14173  * @class Roo.util.ClickRepeater
14174  * @extends Roo.util.Observable
14175  * 
14176  * A wrapper class which can be applied to any element. Fires a "click" event while the
14177  * mouse is pressed. The interval between firings may be specified in the config but
14178  * defaults to 10 milliseconds.
14179  * 
14180  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14181  * 
14182  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14183  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14184  * Similar to an autorepeat key delay.
14185  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14186  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14187  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14188  *           "interval" and "delay" are ignored. "immediate" is honored.
14189  * @cfg {Boolean} preventDefault True to prevent the default click event
14190  * @cfg {Boolean} stopDefault True to stop the default click event
14191  * 
14192  * @history
14193  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14194  *     2007-02-02 jvs Renamed to ClickRepeater
14195  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14196  *
14197  *  @constructor
14198  * @param {String/HTMLElement/Element} el The element to listen on
14199  * @param {Object} config
14200  **/
14201 Roo.util.ClickRepeater = function(el, config)
14202 {
14203     this.el = Roo.get(el);
14204     this.el.unselectable();
14205
14206     Roo.apply(this, config);
14207
14208     this.addEvents({
14209     /**
14210      * @event mousedown
14211      * Fires when the mouse button is depressed.
14212      * @param {Roo.util.ClickRepeater} this
14213      */
14214         "mousedown" : true,
14215     /**
14216      * @event click
14217      * Fires on a specified interval during the time the element is pressed.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "click" : true,
14221     /**
14222      * @event mouseup
14223      * Fires when the mouse key is released.
14224      * @param {Roo.util.ClickRepeater} this
14225      */
14226         "mouseup" : true
14227     });
14228
14229     this.el.on("mousedown", this.handleMouseDown, this);
14230     if(this.preventDefault || this.stopDefault){
14231         this.el.on("click", function(e){
14232             if(this.preventDefault){
14233                 e.preventDefault();
14234             }
14235             if(this.stopDefault){
14236                 e.stopEvent();
14237             }
14238         }, this);
14239     }
14240
14241     // allow inline handler
14242     if(this.handler){
14243         this.on("click", this.handler,  this.scope || this);
14244     }
14245
14246     Roo.util.ClickRepeater.superclass.constructor.call(this);
14247 };
14248
14249 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14250     interval : 20,
14251     delay: 250,
14252     preventDefault : true,
14253     stopDefault : false,
14254     timer : 0,
14255
14256     // private
14257     handleMouseDown : function(){
14258         clearTimeout(this.timer);
14259         this.el.blur();
14260         if(this.pressClass){
14261             this.el.addClass(this.pressClass);
14262         }
14263         this.mousedownTime = new Date();
14264
14265         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14266         this.el.on("mouseout", this.handleMouseOut, this);
14267
14268         this.fireEvent("mousedown", this);
14269         this.fireEvent("click", this);
14270         
14271         this.timer = this.click.defer(this.delay || this.interval, this);
14272     },
14273
14274     // private
14275     click : function(){
14276         this.fireEvent("click", this);
14277         this.timer = this.click.defer(this.getInterval(), this);
14278     },
14279
14280     // private
14281     getInterval: function(){
14282         if(!this.accelerate){
14283             return this.interval;
14284         }
14285         var pressTime = this.mousedownTime.getElapsed();
14286         if(pressTime < 500){
14287             return 400;
14288         }else if(pressTime < 1700){
14289             return 320;
14290         }else if(pressTime < 2600){
14291             return 250;
14292         }else if(pressTime < 3500){
14293             return 180;
14294         }else if(pressTime < 4400){
14295             return 140;
14296         }else if(pressTime < 5300){
14297             return 80;
14298         }else if(pressTime < 6200){
14299             return 50;
14300         }else{
14301             return 10;
14302         }
14303     },
14304
14305     // private
14306     handleMouseOut : function(){
14307         clearTimeout(this.timer);
14308         if(this.pressClass){
14309             this.el.removeClass(this.pressClass);
14310         }
14311         this.el.on("mouseover", this.handleMouseReturn, this);
14312     },
14313
14314     // private
14315     handleMouseReturn : function(){
14316         this.el.un("mouseover", this.handleMouseReturn);
14317         if(this.pressClass){
14318             this.el.addClass(this.pressClass);
14319         }
14320         this.click();
14321     },
14322
14323     // private
14324     handleMouseUp : function(){
14325         clearTimeout(this.timer);
14326         this.el.un("mouseover", this.handleMouseReturn);
14327         this.el.un("mouseout", this.handleMouseOut);
14328         Roo.get(document).un("mouseup", this.handleMouseUp);
14329         this.el.removeClass(this.pressClass);
14330         this.fireEvent("mouseup", this);
14331     }
14332 });/*
14333  * Based on:
14334  * Ext JS Library 1.1.1
14335  * Copyright(c) 2006-2007, Ext JS, LLC.
14336  *
14337  * Originally Released Under LGPL - original licence link has changed is not relivant.
14338  *
14339  * Fork - LGPL
14340  * <script type="text/javascript">
14341  */
14342
14343  
14344 /**
14345  * @class Roo.KeyNav
14346  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14347  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14348  * way to implement custom navigation schemes for any UI component.</p>
14349  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14350  * pageUp, pageDown, del, home, end.  Usage:</p>
14351  <pre><code>
14352 var nav = new Roo.KeyNav("my-element", {
14353     "left" : function(e){
14354         this.moveLeft(e.ctrlKey);
14355     },
14356     "right" : function(e){
14357         this.moveRight(e.ctrlKey);
14358     },
14359     "enter" : function(e){
14360         this.save();
14361     },
14362     scope : this
14363 });
14364 </code></pre>
14365  * @constructor
14366  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14367  * @param {Object} config The config
14368  */
14369 Roo.KeyNav = function(el, config){
14370     this.el = Roo.get(el);
14371     Roo.apply(this, config);
14372     if(!this.disabled){
14373         this.disabled = true;
14374         this.enable();
14375     }
14376 };
14377
14378 Roo.KeyNav.prototype = {
14379     /**
14380      * @cfg {Boolean} disabled
14381      * True to disable this KeyNav instance (defaults to false)
14382      */
14383     disabled : false,
14384     /**
14385      * @cfg {String} defaultEventAction
14386      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14387      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14388      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14389      */
14390     defaultEventAction: "stopEvent",
14391     /**
14392      * @cfg {Boolean} forceKeyDown
14393      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14394      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14395      * handle keydown instead of keypress.
14396      */
14397     forceKeyDown : false,
14398
14399     // private
14400     prepareEvent : function(e){
14401         var k = e.getKey();
14402         var h = this.keyToHandler[k];
14403         //if(h && this[h]){
14404         //    e.stopPropagation();
14405         //}
14406         if(Roo.isSafari && h && k >= 37 && k <= 40){
14407             e.stopEvent();
14408         }
14409     },
14410
14411     // private
14412     relay : function(e){
14413         var k = e.getKey();
14414         var h = this.keyToHandler[k];
14415         if(h && this[h]){
14416             if(this.doRelay(e, this[h], h) !== true){
14417                 e[this.defaultEventAction]();
14418             }
14419         }
14420     },
14421
14422     // private
14423     doRelay : function(e, h, hname){
14424         return h.call(this.scope || this, e);
14425     },
14426
14427     // possible handlers
14428     enter : false,
14429     left : false,
14430     right : false,
14431     up : false,
14432     down : false,
14433     tab : false,
14434     esc : false,
14435     pageUp : false,
14436     pageDown : false,
14437     del : false,
14438     home : false,
14439     end : false,
14440
14441     // quick lookup hash
14442     keyToHandler : {
14443         37 : "left",
14444         39 : "right",
14445         38 : "up",
14446         40 : "down",
14447         33 : "pageUp",
14448         34 : "pageDown",
14449         46 : "del",
14450         36 : "home",
14451         35 : "end",
14452         13 : "enter",
14453         27 : "esc",
14454         9  : "tab"
14455     },
14456
14457         /**
14458          * Enable this KeyNav
14459          */
14460         enable: function(){
14461                 if(this.disabled){
14462             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14463             // the EventObject will normalize Safari automatically
14464             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14465                 this.el.on("keydown", this.relay,  this);
14466             }else{
14467                 this.el.on("keydown", this.prepareEvent,  this);
14468                 this.el.on("keypress", this.relay,  this);
14469             }
14470                     this.disabled = false;
14471                 }
14472         },
14473
14474         /**
14475          * Disable this KeyNav
14476          */
14477         disable: function(){
14478                 if(!this.disabled){
14479                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14480                 this.el.un("keydown", this.relay);
14481             }else{
14482                 this.el.un("keydown", this.prepareEvent);
14483                 this.el.un("keypress", this.relay);
14484             }
14485                     this.disabled = true;
14486                 }
14487         }
14488 };/*
14489  * Based on:
14490  * Ext JS Library 1.1.1
14491  * Copyright(c) 2006-2007, Ext JS, LLC.
14492  *
14493  * Originally Released Under LGPL - original licence link has changed is not relivant.
14494  *
14495  * Fork - LGPL
14496  * <script type="text/javascript">
14497  */
14498
14499  
14500 /**
14501  * @class Roo.KeyMap
14502  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14503  * The constructor accepts the same config object as defined by {@link #addBinding}.
14504  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14505  * combination it will call the function with this signature (if the match is a multi-key
14506  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14507  * A KeyMap can also handle a string representation of keys.<br />
14508  * Usage:
14509  <pre><code>
14510 // map one key by key code
14511 var map = new Roo.KeyMap("my-element", {
14512     key: 13, // or Roo.EventObject.ENTER
14513     fn: myHandler,
14514     scope: myObject
14515 });
14516
14517 // map multiple keys to one action by string
14518 var map = new Roo.KeyMap("my-element", {
14519     key: "a\r\n\t",
14520     fn: myHandler,
14521     scope: myObject
14522 });
14523
14524 // map multiple keys to multiple actions by strings and array of codes
14525 var map = new Roo.KeyMap("my-element", [
14526     {
14527         key: [10,13],
14528         fn: function(){ alert("Return was pressed"); }
14529     }, {
14530         key: "abc",
14531         fn: function(){ alert('a, b or c was pressed'); }
14532     }, {
14533         key: "\t",
14534         ctrl:true,
14535         shift:true,
14536         fn: function(){ alert('Control + shift + tab was pressed.'); }
14537     }
14538 ]);
14539 </code></pre>
14540  * <b>Note: A KeyMap starts enabled</b>
14541  * @constructor
14542  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14543  * @param {Object} config The config (see {@link #addBinding})
14544  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14545  */
14546 Roo.KeyMap = function(el, config, eventName){
14547     this.el  = Roo.get(el);
14548     this.eventName = eventName || "keydown";
14549     this.bindings = [];
14550     if(config){
14551         this.addBinding(config);
14552     }
14553     this.enable();
14554 };
14555
14556 Roo.KeyMap.prototype = {
14557     /**
14558      * True to stop the event from bubbling and prevent the default browser action if the
14559      * key was handled by the KeyMap (defaults to false)
14560      * @type Boolean
14561      */
14562     stopEvent : false,
14563
14564     /**
14565      * Add a new binding to this KeyMap. The following config object properties are supported:
14566      * <pre>
14567 Property    Type             Description
14568 ----------  ---------------  ----------------------------------------------------------------------
14569 key         String/Array     A single keycode or an array of keycodes to handle
14570 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14571 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14572 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14573 fn          Function         The function to call when KeyMap finds the expected key combination
14574 scope       Object           The scope of the callback function
14575 </pre>
14576      *
14577      * Usage:
14578      * <pre><code>
14579 // Create a KeyMap
14580 var map = new Roo.KeyMap(document, {
14581     key: Roo.EventObject.ENTER,
14582     fn: handleKey,
14583     scope: this
14584 });
14585
14586 //Add a new binding to the existing KeyMap later
14587 map.addBinding({
14588     key: 'abc',
14589     shift: true,
14590     fn: handleKey,
14591     scope: this
14592 });
14593 </code></pre>
14594      * @param {Object/Array} config A single KeyMap config or an array of configs
14595      */
14596         addBinding : function(config){
14597         if(config instanceof Array){
14598             for(var i = 0, len = config.length; i < len; i++){
14599                 this.addBinding(config[i]);
14600             }
14601             return;
14602         }
14603         var keyCode = config.key,
14604             shift = config.shift, 
14605             ctrl = config.ctrl, 
14606             alt = config.alt,
14607             fn = config.fn,
14608             scope = config.scope;
14609         if(typeof keyCode == "string"){
14610             var ks = [];
14611             var keyString = keyCode.toUpperCase();
14612             for(var j = 0, len = keyString.length; j < len; j++){
14613                 ks.push(keyString.charCodeAt(j));
14614             }
14615             keyCode = ks;
14616         }
14617         var keyArray = keyCode instanceof Array;
14618         var handler = function(e){
14619             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14620                 var k = e.getKey();
14621                 if(keyArray){
14622                     for(var i = 0, len = keyCode.length; i < len; i++){
14623                         if(keyCode[i] == k){
14624                           if(this.stopEvent){
14625                               e.stopEvent();
14626                           }
14627                           fn.call(scope || window, k, e);
14628                           return;
14629                         }
14630                     }
14631                 }else{
14632                     if(k == keyCode){
14633                         if(this.stopEvent){
14634                            e.stopEvent();
14635                         }
14636                         fn.call(scope || window, k, e);
14637                     }
14638                 }
14639             }
14640         };
14641         this.bindings.push(handler);  
14642         },
14643
14644     /**
14645      * Shorthand for adding a single key listener
14646      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14647      * following options:
14648      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14649      * @param {Function} fn The function to call
14650      * @param {Object} scope (optional) The scope of the function
14651      */
14652     on : function(key, fn, scope){
14653         var keyCode, shift, ctrl, alt;
14654         if(typeof key == "object" && !(key instanceof Array)){
14655             keyCode = key.key;
14656             shift = key.shift;
14657             ctrl = key.ctrl;
14658             alt = key.alt;
14659         }else{
14660             keyCode = key;
14661         }
14662         this.addBinding({
14663             key: keyCode,
14664             shift: shift,
14665             ctrl: ctrl,
14666             alt: alt,
14667             fn: fn,
14668             scope: scope
14669         })
14670     },
14671
14672     // private
14673     handleKeyDown : function(e){
14674             if(this.enabled){ //just in case
14675             var b = this.bindings;
14676             for(var i = 0, len = b.length; i < len; i++){
14677                 b[i].call(this, e);
14678             }
14679             }
14680         },
14681         
14682         /**
14683          * Returns true if this KeyMap is enabled
14684          * @return {Boolean} 
14685          */
14686         isEnabled : function(){
14687             return this.enabled;  
14688         },
14689         
14690         /**
14691          * Enables this KeyMap
14692          */
14693         enable: function(){
14694                 if(!this.enabled){
14695                     this.el.on(this.eventName, this.handleKeyDown, this);
14696                     this.enabled = true;
14697                 }
14698         },
14699
14700         /**
14701          * Disable this KeyMap
14702          */
14703         disable: function(){
14704                 if(this.enabled){
14705                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14706                     this.enabled = false;
14707                 }
14708         }
14709 };/*
14710  * Based on:
14711  * Ext JS Library 1.1.1
14712  * Copyright(c) 2006-2007, Ext JS, LLC.
14713  *
14714  * Originally Released Under LGPL - original licence link has changed is not relivant.
14715  *
14716  * Fork - LGPL
14717  * <script type="text/javascript">
14718  */
14719
14720  
14721 /**
14722  * @class Roo.util.TextMetrics
14723  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14724  * wide, in pixels, a given block of text will be.
14725  * @singleton
14726  */
14727 Roo.util.TextMetrics = function(){
14728     var shared;
14729     return {
14730         /**
14731          * Measures the size of the specified text
14732          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14733          * that can affect the size of the rendered text
14734          * @param {String} text The text to measure
14735          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14736          * in order to accurately measure the text height
14737          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14738          */
14739         measure : function(el, text, fixedWidth){
14740             if(!shared){
14741                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14742             }
14743             shared.bind(el);
14744             shared.setFixedWidth(fixedWidth || 'auto');
14745             return shared.getSize(text);
14746         },
14747
14748         /**
14749          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14750          * the overhead of multiple calls to initialize the style properties on each measurement.
14751          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14752          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14753          * in order to accurately measure the text height
14754          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14755          */
14756         createInstance : function(el, fixedWidth){
14757             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14758         }
14759     };
14760 }();
14761
14762  
14763
14764 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14765     var ml = new Roo.Element(document.createElement('div'));
14766     document.body.appendChild(ml.dom);
14767     ml.position('absolute');
14768     ml.setLeftTop(-1000, -1000);
14769     ml.hide();
14770
14771     if(fixedWidth){
14772         ml.setWidth(fixedWidth);
14773     }
14774      
14775     var instance = {
14776         /**
14777          * Returns the size of the specified text based on the internal element's style and width properties
14778          * @memberOf Roo.util.TextMetrics.Instance#
14779          * @param {String} text The text to measure
14780          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14781          */
14782         getSize : function(text){
14783             ml.update(text);
14784             var s = ml.getSize();
14785             ml.update('');
14786             return s;
14787         },
14788
14789         /**
14790          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14791          * that can affect the size of the rendered text
14792          * @memberOf Roo.util.TextMetrics.Instance#
14793          * @param {String/HTMLElement} el The element, dom node or id
14794          */
14795         bind : function(el){
14796             ml.setStyle(
14797                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14798             );
14799         },
14800
14801         /**
14802          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14803          * to set a fixed width in order to accurately measure the text height.
14804          * @memberOf Roo.util.TextMetrics.Instance#
14805          * @param {Number} width The width to set on the element
14806          */
14807         setFixedWidth : function(width){
14808             ml.setWidth(width);
14809         },
14810
14811         /**
14812          * Returns the measured width of the specified text
14813          * @memberOf Roo.util.TextMetrics.Instance#
14814          * @param {String} text The text to measure
14815          * @return {Number} width The width in pixels
14816          */
14817         getWidth : function(text){
14818             ml.dom.style.width = 'auto';
14819             return this.getSize(text).width;
14820         },
14821
14822         /**
14823          * Returns the measured height of the specified text.  For multiline text, be sure to call
14824          * {@link #setFixedWidth} if necessary.
14825          * @memberOf Roo.util.TextMetrics.Instance#
14826          * @param {String} text The text to measure
14827          * @return {Number} height The height in pixels
14828          */
14829         getHeight : function(text){
14830             return this.getSize(text).height;
14831         }
14832     };
14833
14834     instance.bind(bindTo);
14835
14836     return instance;
14837 };
14838
14839 // backwards compat
14840 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14841  * Based on:
14842  * Ext JS Library 1.1.1
14843  * Copyright(c) 2006-2007, Ext JS, LLC.
14844  *
14845  * Originally Released Under LGPL - original licence link has changed is not relivant.
14846  *
14847  * Fork - LGPL
14848  * <script type="text/javascript">
14849  */
14850
14851 /**
14852  * @class Roo.state.Provider
14853  * Abstract base class for state provider implementations. This class provides methods
14854  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14855  * Provider interface.
14856  */
14857 Roo.state.Provider = function(){
14858     /**
14859      * @event statechange
14860      * Fires when a state change occurs.
14861      * @param {Provider} this This state provider
14862      * @param {String} key The state key which was changed
14863      * @param {String} value The encoded value for the state
14864      */
14865     this.addEvents({
14866         "statechange": true
14867     });
14868     this.state = {};
14869     Roo.state.Provider.superclass.constructor.call(this);
14870 };
14871 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14872     /**
14873      * Returns the current value for a key
14874      * @param {String} name The key name
14875      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14876      * @return {Mixed} The state data
14877      */
14878     get : function(name, defaultValue){
14879         return typeof this.state[name] == "undefined" ?
14880             defaultValue : this.state[name];
14881     },
14882     
14883     /**
14884      * Clears a value from the state
14885      * @param {String} name The key name
14886      */
14887     clear : function(name){
14888         delete this.state[name];
14889         this.fireEvent("statechange", this, name, null);
14890     },
14891     
14892     /**
14893      * Sets the value for a key
14894      * @param {String} name The key name
14895      * @param {Mixed} value The value to set
14896      */
14897     set : function(name, value){
14898         this.state[name] = value;
14899         this.fireEvent("statechange", this, name, value);
14900     },
14901     
14902     /**
14903      * Decodes a string previously encoded with {@link #encodeValue}.
14904      * @param {String} value The value to decode
14905      * @return {Mixed} The decoded value
14906      */
14907     decodeValue : function(cookie){
14908         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14909         var matches = re.exec(unescape(cookie));
14910         if(!matches || !matches[1]) {
14911             return; // non state cookie
14912         }
14913         var type = matches[1];
14914         var v = matches[2];
14915         switch(type){
14916             case "n":
14917                 return parseFloat(v);
14918             case "d":
14919                 return new Date(Date.parse(v));
14920             case "b":
14921                 return (v == "1");
14922             case "a":
14923                 var all = [];
14924                 var values = v.split("^");
14925                 for(var i = 0, len = values.length; i < len; i++){
14926                     all.push(this.decodeValue(values[i]));
14927                 }
14928                 return all;
14929            case "o":
14930                 var all = {};
14931                 var values = v.split("^");
14932                 for(var i = 0, len = values.length; i < len; i++){
14933                     var kv = values[i].split("=");
14934                     all[kv[0]] = this.decodeValue(kv[1]);
14935                 }
14936                 return all;
14937            default:
14938                 return v;
14939         }
14940     },
14941     
14942     /**
14943      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14944      * @param {Mixed} value The value to encode
14945      * @return {String} The encoded value
14946      */
14947     encodeValue : function(v){
14948         var enc;
14949         if(typeof v == "number"){
14950             enc = "n:" + v;
14951         }else if(typeof v == "boolean"){
14952             enc = "b:" + (v ? "1" : "0");
14953         }else if(v instanceof Date){
14954             enc = "d:" + v.toGMTString();
14955         }else if(v instanceof Array){
14956             var flat = "";
14957             for(var i = 0, len = v.length; i < len; i++){
14958                 flat += this.encodeValue(v[i]);
14959                 if(i != len-1) {
14960                     flat += "^";
14961                 }
14962             }
14963             enc = "a:" + flat;
14964         }else if(typeof v == "object"){
14965             var flat = "";
14966             for(var key in v){
14967                 if(typeof v[key] != "function"){
14968                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14969                 }
14970             }
14971             enc = "o:" + flat.substring(0, flat.length-1);
14972         }else{
14973             enc = "s:" + v;
14974         }
14975         return escape(enc);        
14976     }
14977 });
14978
14979 /*
14980  * Based on:
14981  * Ext JS Library 1.1.1
14982  * Copyright(c) 2006-2007, Ext JS, LLC.
14983  *
14984  * Originally Released Under LGPL - original licence link has changed is not relivant.
14985  *
14986  * Fork - LGPL
14987  * <script type="text/javascript">
14988  */
14989 /**
14990  * @class Roo.state.Manager
14991  * This is the global state manager. By default all components that are "state aware" check this class
14992  * for state information if you don't pass them a custom state provider. In order for this class
14993  * to be useful, it must be initialized with a provider when your application initializes.
14994  <pre><code>
14995 // in your initialization function
14996 init : function(){
14997    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14998    ...
14999    // supposed you have a {@link Roo.BorderLayout}
15000    var layout = new Roo.BorderLayout(...);
15001    layout.restoreState();
15002    // or a {Roo.BasicDialog}
15003    var dialog = new Roo.BasicDialog(...);
15004    dialog.restoreState();
15005  </code></pre>
15006  * @singleton
15007  */
15008 Roo.state.Manager = function(){
15009     var provider = new Roo.state.Provider();
15010     
15011     return {
15012         /**
15013          * Configures the default state provider for your application
15014          * @param {Provider} stateProvider The state provider to set
15015          */
15016         setProvider : function(stateProvider){
15017             provider = stateProvider;
15018         },
15019         
15020         /**
15021          * Returns the current value for a key
15022          * @param {String} name The key name
15023          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15024          * @return {Mixed} The state data
15025          */
15026         get : function(key, defaultValue){
15027             return provider.get(key, defaultValue);
15028         },
15029         
15030         /**
15031          * Sets the value for a key
15032          * @param {String} name The key name
15033          * @param {Mixed} value The state data
15034          */
15035          set : function(key, value){
15036             provider.set(key, value);
15037         },
15038         
15039         /**
15040          * Clears a value from the state
15041          * @param {String} name The key name
15042          */
15043         clear : function(key){
15044             provider.clear(key);
15045         },
15046         
15047         /**
15048          * Gets the currently configured state provider
15049          * @return {Provider} The state provider
15050          */
15051         getProvider : function(){
15052             return provider;
15053         }
15054     };
15055 }();
15056 /*
15057  * Based on:
15058  * Ext JS Library 1.1.1
15059  * Copyright(c) 2006-2007, Ext JS, LLC.
15060  *
15061  * Originally Released Under LGPL - original licence link has changed is not relivant.
15062  *
15063  * Fork - LGPL
15064  * <script type="text/javascript">
15065  */
15066 /**
15067  * @class Roo.state.CookieProvider
15068  * @extends Roo.state.Provider
15069  * The default Provider implementation which saves state via cookies.
15070  * <br />Usage:
15071  <pre><code>
15072    var cp = new Roo.state.CookieProvider({
15073        path: "/cgi-bin/",
15074        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15075        domain: "roojs.com"
15076    })
15077    Roo.state.Manager.setProvider(cp);
15078  </code></pre>
15079  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15080  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15081  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15082  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15083  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15084  * domain the page is running on including the 'www' like 'www.roojs.com')
15085  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15086  * @constructor
15087  * Create a new CookieProvider
15088  * @param {Object} config The configuration object
15089  */
15090 Roo.state.CookieProvider = function(config){
15091     Roo.state.CookieProvider.superclass.constructor.call(this);
15092     this.path = "/";
15093     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15094     this.domain = null;
15095     this.secure = false;
15096     Roo.apply(this, config);
15097     this.state = this.readCookies();
15098 };
15099
15100 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15101     // private
15102     set : function(name, value){
15103         if(typeof value == "undefined" || value === null){
15104             this.clear(name);
15105             return;
15106         }
15107         this.setCookie(name, value);
15108         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15109     },
15110
15111     // private
15112     clear : function(name){
15113         this.clearCookie(name);
15114         Roo.state.CookieProvider.superclass.clear.call(this, name);
15115     },
15116
15117     // private
15118     readCookies : function(){
15119         var cookies = {};
15120         var c = document.cookie + ";";
15121         var re = /\s?(.*?)=(.*?);/g;
15122         var matches;
15123         while((matches = re.exec(c)) != null){
15124             var name = matches[1];
15125             var value = matches[2];
15126             if(name && name.substring(0,3) == "ys-"){
15127                 cookies[name.substr(3)] = this.decodeValue(value);
15128             }
15129         }
15130         return cookies;
15131     },
15132
15133     // private
15134     setCookie : function(name, value){
15135         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15136            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15137            ((this.path == null) ? "" : ("; path=" + this.path)) +
15138            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15139            ((this.secure == true) ? "; secure" : "");
15140     },
15141
15142     // private
15143     clearCookie : function(name){
15144         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15145            ((this.path == null) ? "" : ("; path=" + this.path)) +
15146            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15147            ((this.secure == true) ? "; secure" : "");
15148     }
15149 });/*
15150  * Based on:
15151  * Ext JS Library 1.1.1
15152  * Copyright(c) 2006-2007, Ext JS, LLC.
15153  *
15154  * Originally Released Under LGPL - original licence link has changed is not relivant.
15155  *
15156  * Fork - LGPL
15157  * <script type="text/javascript">
15158  */
15159  
15160
15161 /**
15162  * @class Roo.ComponentMgr
15163  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15164  * @singleton
15165  */
15166 Roo.ComponentMgr = function(){
15167     var all = new Roo.util.MixedCollection();
15168
15169     return {
15170         /**
15171          * Registers a component.
15172          * @param {Roo.Component} c The component
15173          */
15174         register : function(c){
15175             all.add(c);
15176         },
15177
15178         /**
15179          * Unregisters a component.
15180          * @param {Roo.Component} c The component
15181          */
15182         unregister : function(c){
15183             all.remove(c);
15184         },
15185
15186         /**
15187          * Returns a component by id
15188          * @param {String} id The component id
15189          */
15190         get : function(id){
15191             return all.get(id);
15192         },
15193
15194         /**
15195          * Registers a function that will be called when a specified component is added to ComponentMgr
15196          * @param {String} id The component id
15197          * @param {Funtction} fn The callback function
15198          * @param {Object} scope The scope of the callback
15199          */
15200         onAvailable : function(id, fn, scope){
15201             all.on("add", function(index, o){
15202                 if(o.id == id){
15203                     fn.call(scope || o, o);
15204                     all.un("add", fn, scope);
15205                 }
15206             });
15207         }
15208     };
15209 }();/*
15210  * Based on:
15211  * Ext JS Library 1.1.1
15212  * Copyright(c) 2006-2007, Ext JS, LLC.
15213  *
15214  * Originally Released Under LGPL - original licence link has changed is not relivant.
15215  *
15216  * Fork - LGPL
15217  * <script type="text/javascript">
15218  */
15219  
15220 /**
15221  * @class Roo.Component
15222  * @extends Roo.util.Observable
15223  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15224  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15225  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15226  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15227  * All visual components (widgets) that require rendering into a layout should subclass Component.
15228  * @constructor
15229  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15230  * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
15231  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15232  */
15233 Roo.Component = function(config){
15234     config = config || {};
15235     if(config.tagName || config.dom || typeof config == "string"){ // element object
15236         config = {el: config, id: config.id || config};
15237     }
15238     this.initialConfig = config;
15239
15240     Roo.apply(this, config);
15241     this.addEvents({
15242         /**
15243          * @event disable
15244          * Fires after the component is disabled.
15245              * @param {Roo.Component} this
15246              */
15247         disable : true,
15248         /**
15249          * @event enable
15250          * Fires after the component is enabled.
15251              * @param {Roo.Component} this
15252              */
15253         enable : true,
15254         /**
15255          * @event beforeshow
15256          * Fires before the component is shown.  Return false to stop the show.
15257              * @param {Roo.Component} this
15258              */
15259         beforeshow : true,
15260         /**
15261          * @event show
15262          * Fires after the component is shown.
15263              * @param {Roo.Component} this
15264              */
15265         show : true,
15266         /**
15267          * @event beforehide
15268          * Fires before the component is hidden. Return false to stop the hide.
15269              * @param {Roo.Component} this
15270              */
15271         beforehide : true,
15272         /**
15273          * @event hide
15274          * Fires after the component is hidden.
15275              * @param {Roo.Component} this
15276              */
15277         hide : true,
15278         /**
15279          * @event beforerender
15280          * Fires before the component is rendered. Return false to stop the render.
15281              * @param {Roo.Component} this
15282              */
15283         beforerender : true,
15284         /**
15285          * @event render
15286          * Fires after the component is rendered.
15287              * @param {Roo.Component} this
15288              */
15289         render : true,
15290         /**
15291          * @event beforedestroy
15292          * Fires before the component is destroyed. Return false to stop the destroy.
15293              * @param {Roo.Component} this
15294              */
15295         beforedestroy : true,
15296         /**
15297          * @event destroy
15298          * Fires after the component is destroyed.
15299              * @param {Roo.Component} this
15300              */
15301         destroy : true
15302     });
15303     if(!this.id){
15304         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15305     }
15306     Roo.ComponentMgr.register(this);
15307     Roo.Component.superclass.constructor.call(this);
15308     this.initComponent();
15309     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15310         this.render(this.renderTo);
15311         delete this.renderTo;
15312     }
15313 };
15314
15315 /** @private */
15316 Roo.Component.AUTO_ID = 1000;
15317
15318 Roo.extend(Roo.Component, Roo.util.Observable, {
15319     /**
15320      * @scope Roo.Component.prototype
15321      * @type {Boolean}
15322      * true if this component is hidden. Read-only.
15323      */
15324     hidden : false,
15325     /**
15326      * @type {Boolean}
15327      * true if this component is disabled. Read-only.
15328      */
15329     disabled : false,
15330     /**
15331      * @type {Boolean}
15332      * true if this component has been rendered. Read-only.
15333      */
15334     rendered : false,
15335     
15336     /** @cfg {String} disableClass
15337      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15338      */
15339     disabledClass : "x-item-disabled",
15340         /** @cfg {Boolean} allowDomMove
15341          * Whether the component can move the Dom node when rendering (defaults to true).
15342          */
15343     allowDomMove : true,
15344     /** @cfg {String} hideMode (display|visibility)
15345      * How this component should hidden. Supported values are
15346      * "visibility" (css visibility), "offsets" (negative offset position) and
15347      * "display" (css display) - defaults to "display".
15348      */
15349     hideMode: 'display',
15350
15351     /** @private */
15352     ctype : "Roo.Component",
15353
15354     /**
15355      * @cfg {String} actionMode 
15356      * which property holds the element that used for  hide() / show() / disable() / enable()
15357      * default is 'el' 
15358      */
15359     actionMode : "el",
15360
15361     /** @private */
15362     getActionEl : function(){
15363         return this[this.actionMode];
15364     },
15365
15366     initComponent : Roo.emptyFn,
15367     /**
15368      * If this is a lazy rendering component, render it to its container element.
15369      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15370      */
15371     render : function(container, position){
15372         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15373             if(!container && this.el){
15374                 this.el = Roo.get(this.el);
15375                 container = this.el.dom.parentNode;
15376                 this.allowDomMove = false;
15377             }
15378             this.container = Roo.get(container);
15379             this.rendered = true;
15380             if(position !== undefined){
15381                 if(typeof position == 'number'){
15382                     position = this.container.dom.childNodes[position];
15383                 }else{
15384                     position = Roo.getDom(position);
15385                 }
15386             }
15387             this.onRender(this.container, position || null);
15388             if(this.cls){
15389                 this.el.addClass(this.cls);
15390                 delete this.cls;
15391             }
15392             if(this.style){
15393                 this.el.applyStyles(this.style);
15394                 delete this.style;
15395             }
15396             this.fireEvent("render", this);
15397             this.afterRender(this.container);
15398             if(this.hidden){
15399                 this.hide();
15400             }
15401             if(this.disabled){
15402                 this.disable();
15403             }
15404         }
15405         return this;
15406     },
15407
15408     /** @private */
15409     // default function is not really useful
15410     onRender : function(ct, position){
15411         if(this.el){
15412             this.el = Roo.get(this.el);
15413             if(this.allowDomMove !== false){
15414                 ct.dom.insertBefore(this.el.dom, position);
15415             }
15416         }
15417     },
15418
15419     /** @private */
15420     getAutoCreate : function(){
15421         var cfg = typeof this.autoCreate == "object" ?
15422                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15423         if(this.id && !cfg.id){
15424             cfg.id = this.id;
15425         }
15426         return cfg;
15427     },
15428
15429     /** @private */
15430     afterRender : Roo.emptyFn,
15431
15432     /**
15433      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15434      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15435      */
15436     destroy : function(){
15437         if(this.fireEvent("beforedestroy", this) !== false){
15438             this.purgeListeners();
15439             this.beforeDestroy();
15440             if(this.rendered){
15441                 this.el.removeAllListeners();
15442                 this.el.remove();
15443                 if(this.actionMode == "container"){
15444                     this.container.remove();
15445                 }
15446             }
15447             this.onDestroy();
15448             Roo.ComponentMgr.unregister(this);
15449             this.fireEvent("destroy", this);
15450         }
15451     },
15452
15453         /** @private */
15454     beforeDestroy : function(){
15455
15456     },
15457
15458         /** @private */
15459         onDestroy : function(){
15460
15461     },
15462
15463     /**
15464      * Returns the underlying {@link Roo.Element}.
15465      * @return {Roo.Element} The element
15466      */
15467     getEl : function(){
15468         return this.el;
15469     },
15470
15471     /**
15472      * Returns the id of this component.
15473      * @return {String}
15474      */
15475     getId : function(){
15476         return this.id;
15477     },
15478
15479     /**
15480      * Try to focus this component.
15481      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15482      * @return {Roo.Component} this
15483      */
15484     focus : function(selectText){
15485         if(this.rendered){
15486             this.el.focus();
15487             if(selectText === true){
15488                 this.el.dom.select();
15489             }
15490         }
15491         return this;
15492     },
15493
15494     /** @private */
15495     blur : function(){
15496         if(this.rendered){
15497             this.el.blur();
15498         }
15499         return this;
15500     },
15501
15502     /**
15503      * Disable this component.
15504      * @return {Roo.Component} this
15505      */
15506     disable : function(){
15507         if(this.rendered){
15508             this.onDisable();
15509         }
15510         this.disabled = true;
15511         this.fireEvent("disable", this);
15512         return this;
15513     },
15514
15515         // private
15516     onDisable : function(){
15517         this.getActionEl().addClass(this.disabledClass);
15518         this.el.dom.disabled = true;
15519     },
15520
15521     /**
15522      * Enable this component.
15523      * @return {Roo.Component} this
15524      */
15525     enable : function(){
15526         if(this.rendered){
15527             this.onEnable();
15528         }
15529         this.disabled = false;
15530         this.fireEvent("enable", this);
15531         return this;
15532     },
15533
15534         // private
15535     onEnable : function(){
15536         this.getActionEl().removeClass(this.disabledClass);
15537         this.el.dom.disabled = false;
15538     },
15539
15540     /**
15541      * Convenience function for setting disabled/enabled by boolean.
15542      * @param {Boolean} disabled
15543      */
15544     setDisabled : function(disabled){
15545         this[disabled ? "disable" : "enable"]();
15546     },
15547
15548     /**
15549      * Show this component.
15550      * @return {Roo.Component} this
15551      */
15552     show: function(){
15553         if(this.fireEvent("beforeshow", this) !== false){
15554             this.hidden = false;
15555             if(this.rendered){
15556                 this.onShow();
15557             }
15558             this.fireEvent("show", this);
15559         }
15560         return this;
15561     },
15562
15563     // private
15564     onShow : function(){
15565         var ae = this.getActionEl();
15566         if(this.hideMode == 'visibility'){
15567             ae.dom.style.visibility = "visible";
15568         }else if(this.hideMode == 'offsets'){
15569             ae.removeClass('x-hidden');
15570         }else{
15571             ae.dom.style.display = "";
15572         }
15573     },
15574
15575     /**
15576      * Hide this component.
15577      * @return {Roo.Component} this
15578      */
15579     hide: function(){
15580         if(this.fireEvent("beforehide", this) !== false){
15581             this.hidden = true;
15582             if(this.rendered){
15583                 this.onHide();
15584             }
15585             this.fireEvent("hide", this);
15586         }
15587         return this;
15588     },
15589
15590     // private
15591     onHide : function(){
15592         var ae = this.getActionEl();
15593         if(this.hideMode == 'visibility'){
15594             ae.dom.style.visibility = "hidden";
15595         }else if(this.hideMode == 'offsets'){
15596             ae.addClass('x-hidden');
15597         }else{
15598             ae.dom.style.display = "none";
15599         }
15600     },
15601
15602     /**
15603      * Convenience function to hide or show this component by boolean.
15604      * @param {Boolean} visible True to show, false to hide
15605      * @return {Roo.Component} this
15606      */
15607     setVisible: function(visible){
15608         if(visible) {
15609             this.show();
15610         }else{
15611             this.hide();
15612         }
15613         return this;
15614     },
15615
15616     /**
15617      * Returns true if this component is visible.
15618      */
15619     isVisible : function(){
15620         return this.getActionEl().isVisible();
15621     },
15622
15623     cloneConfig : function(overrides){
15624         overrides = overrides || {};
15625         var id = overrides.id || Roo.id();
15626         var cfg = Roo.applyIf(overrides, this.initialConfig);
15627         cfg.id = id; // prevent dup id
15628         return new this.constructor(cfg);
15629     }
15630 });/*
15631  * Based on:
15632  * Ext JS Library 1.1.1
15633  * Copyright(c) 2006-2007, Ext JS, LLC.
15634  *
15635  * Originally Released Under LGPL - original licence link has changed is not relivant.
15636  *
15637  * Fork - LGPL
15638  * <script type="text/javascript">
15639  */
15640
15641 /**
15642  * @class Roo.BoxComponent
15643  * @extends Roo.Component
15644  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15645  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15646  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15647  * layout containers.
15648  * @constructor
15649  * @param {Roo.Element/String/Object} config The configuration options.
15650  */
15651 Roo.BoxComponent = function(config){
15652     Roo.Component.call(this, config);
15653     this.addEvents({
15654         /**
15655          * @event resize
15656          * Fires after the component is resized.
15657              * @param {Roo.Component} this
15658              * @param {Number} adjWidth The box-adjusted width that was set
15659              * @param {Number} adjHeight The box-adjusted height that was set
15660              * @param {Number} rawWidth The width that was originally specified
15661              * @param {Number} rawHeight The height that was originally specified
15662              */
15663         resize : true,
15664         /**
15665          * @event move
15666          * Fires after the component is moved.
15667              * @param {Roo.Component} this
15668              * @param {Number} x The new x position
15669              * @param {Number} y The new y position
15670              */
15671         move : true
15672     });
15673 };
15674
15675 Roo.extend(Roo.BoxComponent, Roo.Component, {
15676     // private, set in afterRender to signify that the component has been rendered
15677     boxReady : false,
15678     // private, used to defer height settings to subclasses
15679     deferHeight: false,
15680     /** @cfg {Number} width
15681      * width (optional) size of component
15682      */
15683      /** @cfg {Number} height
15684      * height (optional) size of component
15685      */
15686      
15687     /**
15688      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15689      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15690      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15691      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15692      * @return {Roo.BoxComponent} this
15693      */
15694     setSize : function(w, h){
15695         // support for standard size objects
15696         if(typeof w == 'object'){
15697             h = w.height;
15698             w = w.width;
15699         }
15700         // not rendered
15701         if(!this.boxReady){
15702             this.width = w;
15703             this.height = h;
15704             return this;
15705         }
15706
15707         // prevent recalcs when not needed
15708         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15709             return this;
15710         }
15711         this.lastSize = {width: w, height: h};
15712
15713         var adj = this.adjustSize(w, h);
15714         var aw = adj.width, ah = adj.height;
15715         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15716             var rz = this.getResizeEl();
15717             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15718                 rz.setSize(aw, ah);
15719             }else if(!this.deferHeight && ah !== undefined){
15720                 rz.setHeight(ah);
15721             }else if(aw !== undefined){
15722                 rz.setWidth(aw);
15723             }
15724             this.onResize(aw, ah, w, h);
15725             this.fireEvent('resize', this, aw, ah, w, h);
15726         }
15727         return this;
15728     },
15729
15730     /**
15731      * Gets the current size of the component's underlying element.
15732      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15733      */
15734     getSize : function(){
15735         return this.el.getSize();
15736     },
15737
15738     /**
15739      * Gets the current XY position of the component's underlying element.
15740      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15741      * @return {Array} The XY position of the element (e.g., [100, 200])
15742      */
15743     getPosition : function(local){
15744         if(local === true){
15745             return [this.el.getLeft(true), this.el.getTop(true)];
15746         }
15747         return this.xy || this.el.getXY();
15748     },
15749
15750     /**
15751      * Gets the current box measurements of the component's underlying element.
15752      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15753      * @returns {Object} box An object in the format {x, y, width, height}
15754      */
15755     getBox : function(local){
15756         var s = this.el.getSize();
15757         if(local){
15758             s.x = this.el.getLeft(true);
15759             s.y = this.el.getTop(true);
15760         }else{
15761             var xy = this.xy || this.el.getXY();
15762             s.x = xy[0];
15763             s.y = xy[1];
15764         }
15765         return s;
15766     },
15767
15768     /**
15769      * Sets the current box measurements of the component's underlying element.
15770      * @param {Object} box An object in the format {x, y, width, height}
15771      * @returns {Roo.BoxComponent} this
15772      */
15773     updateBox : function(box){
15774         this.setSize(box.width, box.height);
15775         this.setPagePosition(box.x, box.y);
15776         return this;
15777     },
15778
15779     // protected
15780     getResizeEl : function(){
15781         return this.resizeEl || this.el;
15782     },
15783
15784     // protected
15785     getPositionEl : function(){
15786         return this.positionEl || this.el;
15787     },
15788
15789     /**
15790      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15791      * This method fires the move event.
15792      * @param {Number} left The new left
15793      * @param {Number} top The new top
15794      * @returns {Roo.BoxComponent} this
15795      */
15796     setPosition : function(x, y){
15797         this.x = x;
15798         this.y = y;
15799         if(!this.boxReady){
15800             return this;
15801         }
15802         var adj = this.adjustPosition(x, y);
15803         var ax = adj.x, ay = adj.y;
15804
15805         var el = this.getPositionEl();
15806         if(ax !== undefined || ay !== undefined){
15807             if(ax !== undefined && ay !== undefined){
15808                 el.setLeftTop(ax, ay);
15809             }else if(ax !== undefined){
15810                 el.setLeft(ax);
15811             }else if(ay !== undefined){
15812                 el.setTop(ay);
15813             }
15814             this.onPosition(ax, ay);
15815             this.fireEvent('move', this, ax, ay);
15816         }
15817         return this;
15818     },
15819
15820     /**
15821      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15822      * This method fires the move event.
15823      * @param {Number} x The new x position
15824      * @param {Number} y The new y position
15825      * @returns {Roo.BoxComponent} this
15826      */
15827     setPagePosition : function(x, y){
15828         this.pageX = x;
15829         this.pageY = y;
15830         if(!this.boxReady){
15831             return;
15832         }
15833         if(x === undefined || y === undefined){ // cannot translate undefined points
15834             return;
15835         }
15836         var p = this.el.translatePoints(x, y);
15837         this.setPosition(p.left, p.top);
15838         return this;
15839     },
15840
15841     // private
15842     onRender : function(ct, position){
15843         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15844         if(this.resizeEl){
15845             this.resizeEl = Roo.get(this.resizeEl);
15846         }
15847         if(this.positionEl){
15848             this.positionEl = Roo.get(this.positionEl);
15849         }
15850     },
15851
15852     // private
15853     afterRender : function(){
15854         Roo.BoxComponent.superclass.afterRender.call(this);
15855         this.boxReady = true;
15856         this.setSize(this.width, this.height);
15857         if(this.x || this.y){
15858             this.setPosition(this.x, this.y);
15859         }
15860         if(this.pageX || this.pageY){
15861             this.setPagePosition(this.pageX, this.pageY);
15862         }
15863     },
15864
15865     /**
15866      * Force the component's size to recalculate based on the underlying element's current height and width.
15867      * @returns {Roo.BoxComponent} this
15868      */
15869     syncSize : function(){
15870         delete this.lastSize;
15871         this.setSize(this.el.getWidth(), this.el.getHeight());
15872         return this;
15873     },
15874
15875     /**
15876      * Called after the component is resized, this method is empty by default but can be implemented by any
15877      * subclass that needs to perform custom logic after a resize occurs.
15878      * @param {Number} adjWidth The box-adjusted width that was set
15879      * @param {Number} adjHeight The box-adjusted height that was set
15880      * @param {Number} rawWidth The width that was originally specified
15881      * @param {Number} rawHeight The height that was originally specified
15882      */
15883     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15884
15885     },
15886
15887     /**
15888      * Called after the component is moved, this method is empty by default but can be implemented by any
15889      * subclass that needs to perform custom logic after a move occurs.
15890      * @param {Number} x The new x position
15891      * @param {Number} y The new y position
15892      */
15893     onPosition : function(x, y){
15894
15895     },
15896
15897     // private
15898     adjustSize : function(w, h){
15899         if(this.autoWidth){
15900             w = 'auto';
15901         }
15902         if(this.autoHeight){
15903             h = 'auto';
15904         }
15905         return {width : w, height: h};
15906     },
15907
15908     // private
15909     adjustPosition : function(x, y){
15910         return {x : x, y: y};
15911     }
15912 });/*
15913  * Original code for Roojs - LGPL
15914  * <script type="text/javascript">
15915  */
15916  
15917 /**
15918  * @class Roo.XComponent
15919  * A delayed Element creator...
15920  * Or a way to group chunks of interface together.
15921  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15922  *  used in conjunction with XComponent.build() it will create an instance of each element,
15923  *  then call addxtype() to build the User interface.
15924  * 
15925  * Mypart.xyx = new Roo.XComponent({
15926
15927     parent : 'Mypart.xyz', // empty == document.element.!!
15928     order : '001',
15929     name : 'xxxx'
15930     region : 'xxxx'
15931     disabled : function() {} 
15932      
15933     tree : function() { // return an tree of xtype declared components
15934         var MODULE = this;
15935         return 
15936         {
15937             xtype : 'NestedLayoutPanel',
15938             // technicall
15939         }
15940      ]
15941  *})
15942  *
15943  *
15944  * It can be used to build a big heiracy, with parent etc.
15945  * or you can just use this to render a single compoent to a dom element
15946  * MYPART.render(Roo.Element | String(id) | dom_element )
15947  *
15948  *
15949  * Usage patterns.
15950  *
15951  * Classic Roo
15952  *
15953  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15954  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15955  *
15956  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15957  *
15958  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15959  * - if mulitple topModules exist, the last one is defined as the top module.
15960  *
15961  * Embeded Roo
15962  * 
15963  * When the top level or multiple modules are to embedded into a existing HTML page,
15964  * the parent element can container '#id' of the element where the module will be drawn.
15965  *
15966  * Bootstrap Roo
15967  *
15968  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15969  * it relies more on a include mechanism, where sub modules are included into an outer page.
15970  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15971  * 
15972  * Bootstrap Roo Included elements
15973  *
15974  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15975  * hence confusing the component builder as it thinks there are multiple top level elements. 
15976  *
15977  * 
15978  * 
15979  * @extends Roo.util.Observable
15980  * @constructor
15981  * @param cfg {Object} configuration of component
15982  * 
15983  */
15984 Roo.XComponent = function(cfg) {
15985     Roo.apply(this, cfg);
15986     this.addEvents({ 
15987         /**
15988              * @event built
15989              * Fires when this the componnt is built
15990              * @param {Roo.XComponent} c the component
15991              */
15992         'built' : true
15993         
15994     });
15995     this.region = this.region || 'center'; // default..
15996     Roo.XComponent.register(this);
15997     this.modules = false;
15998     this.el = false; // where the layout goes..
15999     
16000     
16001 }
16002 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16003     /**
16004      * @property el
16005      * The created element (with Roo.factory())
16006      * @type {Roo.Layout}
16007      */
16008     el  : false,
16009     
16010     /**
16011      * @property el
16012      * for BC  - use el in new code
16013      * @type {Roo.Layout}
16014      */
16015     panel : false,
16016     
16017     /**
16018      * @property layout
16019      * for BC  - use el in new code
16020      * @type {Roo.Layout}
16021      */
16022     layout : false,
16023     
16024      /**
16025      * @cfg {Function|boolean} disabled
16026      * If this module is disabled by some rule, return true from the funtion
16027      */
16028     disabled : false,
16029     
16030     /**
16031      * @cfg {String} parent 
16032      * Name of parent element which it get xtype added to..
16033      */
16034     parent: false,
16035     
16036     /**
16037      * @cfg {String} order
16038      * Used to set the order in which elements are created (usefull for multiple tabs)
16039      */
16040     
16041     order : false,
16042     /**
16043      * @cfg {String} name
16044      * String to display while loading.
16045      */
16046     name : false,
16047     /**
16048      * @cfg {String} region
16049      * Region to render component to (defaults to center)
16050      */
16051     region : 'center',
16052     
16053     /**
16054      * @cfg {Array} items
16055      * A single item array - the first element is the root of the tree..
16056      * It's done this way to stay compatible with the Xtype system...
16057      */
16058     items : false,
16059     
16060     /**
16061      * @property _tree
16062      * The method that retuns the tree of parts that make up this compoennt 
16063      * @type {function}
16064      */
16065     _tree  : false,
16066     
16067      /**
16068      * render
16069      * render element to dom or tree
16070      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16071      */
16072     
16073     render : function(el)
16074     {
16075         
16076         el = el || false;
16077         var hp = this.parent ? 1 : 0;
16078         Roo.debug &&  Roo.log(this);
16079         
16080         var tree = this._tree ? this._tree() : this.tree();
16081
16082         
16083         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16084             // if parent is a '#.....' string, then let's use that..
16085             var ename = this.parent.substr(1);
16086             this.parent = false;
16087             Roo.debug && Roo.log(ename);
16088             switch (ename) {
16089                 case 'bootstrap-body':
16090                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16091                         // this is the BorderLayout standard?
16092                        this.parent = { el : true };
16093                        break;
16094                     }
16095                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16096                         // need to insert stuff...
16097                         this.parent =  {
16098                              el : new Roo.bootstrap.layout.Border({
16099                                  el : document.body, 
16100                      
16101                                  center: {
16102                                     titlebar: false,
16103                                     autoScroll:false,
16104                                     closeOnTab: true,
16105                                     tabPosition: 'top',
16106                                       //resizeTabs: true,
16107                                     alwaysShowTabs: true,
16108                                     hideTabs: false
16109                                      //minTabWidth: 140
16110                                  }
16111                              })
16112                         
16113                          };
16114                          break;
16115                     }
16116                          
16117                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16118                         this.parent = { el :  new  Roo.bootstrap.Body() };
16119                         Roo.debug && Roo.log("setting el to doc body");
16120                          
16121                     } else {
16122                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16123                     }
16124                     break;
16125                 case 'bootstrap':
16126                     this.parent = { el : true};
16127                     // fall through
16128                 default:
16129                     el = Roo.get(ename);
16130                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16131                         this.parent = { el : true};
16132                     }
16133                     
16134                     break;
16135             }
16136                 
16137             
16138             if (!el && !this.parent) {
16139                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16140                 return;
16141             }
16142         }
16143         
16144         Roo.debug && Roo.log("EL:");
16145         Roo.debug && Roo.log(el);
16146         Roo.debug && Roo.log("this.parent.el:");
16147         Roo.debug && Roo.log(this.parent.el);
16148         
16149
16150         // altertive root elements ??? - we need a better way to indicate these.
16151         var is_alt = Roo.XComponent.is_alt ||
16152                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16153                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16154                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16155         
16156         
16157         
16158         if (!this.parent && is_alt) {
16159             //el = Roo.get(document.body);
16160             this.parent = { el : true };
16161         }
16162             
16163             
16164         
16165         if (!this.parent) {
16166             
16167             Roo.debug && Roo.log("no parent - creating one");
16168             
16169             el = el ? Roo.get(el) : false;      
16170             
16171             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16172                 
16173                 this.parent =  {
16174                     el : new Roo.bootstrap.layout.Border({
16175                         el: el || document.body,
16176                     
16177                         center: {
16178                             titlebar: false,
16179                             autoScroll:false,
16180                             closeOnTab: true,
16181                             tabPosition: 'top',
16182                              //resizeTabs: true,
16183                             alwaysShowTabs: false,
16184                             hideTabs: true,
16185                             minTabWidth: 140,
16186                             overflow: 'visible'
16187                          }
16188                      })
16189                 };
16190             } else {
16191             
16192                 // it's a top level one..
16193                 this.parent =  {
16194                     el : new Roo.BorderLayout(el || document.body, {
16195                         center: {
16196                             titlebar: false,
16197                             autoScroll:false,
16198                             closeOnTab: true,
16199                             tabPosition: 'top',
16200                              //resizeTabs: true,
16201                             alwaysShowTabs: el && hp? false :  true,
16202                             hideTabs: el || !hp ? true :  false,
16203                             minTabWidth: 140
16204                          }
16205                     })
16206                 };
16207             }
16208         }
16209         
16210         if (!this.parent.el) {
16211                 // probably an old style ctor, which has been disabled.
16212                 return;
16213
16214         }
16215                 // The 'tree' method is  '_tree now' 
16216             
16217         tree.region = tree.region || this.region;
16218         var is_body = false;
16219         if (this.parent.el === true) {
16220             // bootstrap... - body..
16221             if (el) {
16222                 tree.el = el;
16223             }
16224             this.parent.el = Roo.factory(tree);
16225             is_body = true;
16226         }
16227         
16228         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16229         this.fireEvent('built', this);
16230         
16231         this.panel = this.el;
16232         this.layout = this.panel.layout;
16233         this.parentLayout = this.parent.layout  || false;  
16234          
16235     }
16236     
16237 });
16238
16239 Roo.apply(Roo.XComponent, {
16240     /**
16241      * @property  hideProgress
16242      * true to disable the building progress bar.. usefull on single page renders.
16243      * @type Boolean
16244      */
16245     hideProgress : false,
16246     /**
16247      * @property  buildCompleted
16248      * True when the builder has completed building the interface.
16249      * @type Boolean
16250      */
16251     buildCompleted : false,
16252      
16253     /**
16254      * @property  topModule
16255      * the upper most module - uses document.element as it's constructor.
16256      * @type Object
16257      */
16258      
16259     topModule  : false,
16260       
16261     /**
16262      * @property  modules
16263      * array of modules to be created by registration system.
16264      * @type {Array} of Roo.XComponent
16265      */
16266     
16267     modules : [],
16268     /**
16269      * @property  elmodules
16270      * array of modules to be created by which use #ID 
16271      * @type {Array} of Roo.XComponent
16272      */
16273      
16274     elmodules : [],
16275
16276      /**
16277      * @property  is_alt
16278      * Is an alternative Root - normally used by bootstrap or other systems,
16279      *    where the top element in the tree can wrap 'body' 
16280      * @type {boolean}  (default false)
16281      */
16282      
16283     is_alt : false,
16284     /**
16285      * @property  build_from_html
16286      * Build elements from html - used by bootstrap HTML stuff 
16287      *    - this is cleared after build is completed
16288      * @type {boolean}    (default false)
16289      */
16290      
16291     build_from_html : false,
16292     /**
16293      * Register components to be built later.
16294      *
16295      * This solves the following issues
16296      * - Building is not done on page load, but after an authentication process has occured.
16297      * - Interface elements are registered on page load
16298      * - Parent Interface elements may not be loaded before child, so this handles that..
16299      * 
16300      *
16301      * example:
16302      * 
16303      * MyApp.register({
16304           order : '000001',
16305           module : 'Pman.Tab.projectMgr',
16306           region : 'center',
16307           parent : 'Pman.layout',
16308           disabled : false,  // or use a function..
16309         })
16310      
16311      * * @param {Object} details about module
16312      */
16313     register : function(obj) {
16314                 
16315         Roo.XComponent.event.fireEvent('register', obj);
16316         switch(typeof(obj.disabled) ) {
16317                 
16318             case 'undefined':
16319                 break;
16320             
16321             case 'function':
16322                 if ( obj.disabled() ) {
16323                         return;
16324                 }
16325                 break;
16326             
16327             default:
16328                 if (obj.disabled) {
16329                         return;
16330                 }
16331                 break;
16332         }
16333                 
16334         this.modules.push(obj);
16335          
16336     },
16337     /**
16338      * convert a string to an object..
16339      * eg. 'AAA.BBB' -> finds AAA.BBB
16340
16341      */
16342     
16343     toObject : function(str)
16344     {
16345         if (!str || typeof(str) == 'object') {
16346             return str;
16347         }
16348         if (str.substring(0,1) == '#') {
16349             return str;
16350         }
16351
16352         var ar = str.split('.');
16353         var rt, o;
16354         rt = ar.shift();
16355             /** eval:var:o */
16356         try {
16357             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16358         } catch (e) {
16359             throw "Module not found : " + str;
16360         }
16361         
16362         if (o === false) {
16363             throw "Module not found : " + str;
16364         }
16365         Roo.each(ar, function(e) {
16366             if (typeof(o[e]) == 'undefined') {
16367                 throw "Module not found : " + str;
16368             }
16369             o = o[e];
16370         });
16371         
16372         return o;
16373         
16374     },
16375     
16376     
16377     /**
16378      * move modules into their correct place in the tree..
16379      * 
16380      */
16381     preBuild : function ()
16382     {
16383         var _t = this;
16384         Roo.each(this.modules , function (obj)
16385         {
16386             Roo.XComponent.event.fireEvent('beforebuild', obj);
16387             
16388             var opar = obj.parent;
16389             try { 
16390                 obj.parent = this.toObject(opar);
16391             } catch(e) {
16392                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16393                 return;
16394             }
16395             
16396             if (!obj.parent) {
16397                 Roo.debug && Roo.log("GOT top level module");
16398                 Roo.debug && Roo.log(obj);
16399                 obj.modules = new Roo.util.MixedCollection(false, 
16400                     function(o) { return o.order + '' }
16401                 );
16402                 this.topModule = obj;
16403                 return;
16404             }
16405                         // parent is a string (usually a dom element name..)
16406             if (typeof(obj.parent) == 'string') {
16407                 this.elmodules.push(obj);
16408                 return;
16409             }
16410             if (obj.parent.constructor != Roo.XComponent) {
16411                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16412             }
16413             if (!obj.parent.modules) {
16414                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16415                     function(o) { return o.order + '' }
16416                 );
16417             }
16418             if (obj.parent.disabled) {
16419                 obj.disabled = true;
16420             }
16421             obj.parent.modules.add(obj);
16422         }, this);
16423     },
16424     
16425      /**
16426      * make a list of modules to build.
16427      * @return {Array} list of modules. 
16428      */ 
16429     
16430     buildOrder : function()
16431     {
16432         var _this = this;
16433         var cmp = function(a,b) {   
16434             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16435         };
16436         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16437             throw "No top level modules to build";
16438         }
16439         
16440         // make a flat list in order of modules to build.
16441         var mods = this.topModule ? [ this.topModule ] : [];
16442                 
16443         
16444         // elmodules (is a list of DOM based modules )
16445         Roo.each(this.elmodules, function(e) {
16446             mods.push(e);
16447             if (!this.topModule &&
16448                 typeof(e.parent) == 'string' &&
16449                 e.parent.substring(0,1) == '#' &&
16450                 Roo.get(e.parent.substr(1))
16451                ) {
16452                 
16453                 _this.topModule = e;
16454             }
16455             
16456         });
16457
16458         
16459         // add modules to their parents..
16460         var addMod = function(m) {
16461             Roo.debug && Roo.log("build Order: add: " + m.name);
16462                 
16463             mods.push(m);
16464             if (m.modules && !m.disabled) {
16465                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16466                 m.modules.keySort('ASC',  cmp );
16467                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16468     
16469                 m.modules.each(addMod);
16470             } else {
16471                 Roo.debug && Roo.log("build Order: no child modules");
16472             }
16473             // not sure if this is used any more..
16474             if (m.finalize) {
16475                 m.finalize.name = m.name + " (clean up) ";
16476                 mods.push(m.finalize);
16477             }
16478             
16479         }
16480         if (this.topModule && this.topModule.modules) { 
16481             this.topModule.modules.keySort('ASC',  cmp );
16482             this.topModule.modules.each(addMod);
16483         } 
16484         return mods;
16485     },
16486     
16487      /**
16488      * Build the registered modules.
16489      * @param {Object} parent element.
16490      * @param {Function} optional method to call after module has been added.
16491      * 
16492      */ 
16493    
16494     build : function(opts) 
16495     {
16496         
16497         if (typeof(opts) != 'undefined') {
16498             Roo.apply(this,opts);
16499         }
16500         
16501         this.preBuild();
16502         var mods = this.buildOrder();
16503       
16504         //this.allmods = mods;
16505         //Roo.debug && Roo.log(mods);
16506         //return;
16507         if (!mods.length) { // should not happen
16508             throw "NO modules!!!";
16509         }
16510         
16511         
16512         var msg = "Building Interface...";
16513         // flash it up as modal - so we store the mask!?
16514         if (!this.hideProgress && Roo.MessageBox) {
16515             Roo.MessageBox.show({ title: 'loading' });
16516             Roo.MessageBox.show({
16517                title: "Please wait...",
16518                msg: msg,
16519                width:450,
16520                progress:true,
16521                closable:false,
16522                modal: false
16523               
16524             });
16525         }
16526         var total = mods.length;
16527         
16528         var _this = this;
16529         var progressRun = function() {
16530             if (!mods.length) {
16531                 Roo.debug && Roo.log('hide?');
16532                 if (!this.hideProgress && Roo.MessageBox) {
16533                     Roo.MessageBox.hide();
16534                 }
16535                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16536                 
16537                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16538                 
16539                 // THE END...
16540                 return false;   
16541             }
16542             
16543             var m = mods.shift();
16544             
16545             
16546             Roo.debug && Roo.log(m);
16547             // not sure if this is supported any more.. - modules that are are just function
16548             if (typeof(m) == 'function') { 
16549                 m.call(this);
16550                 return progressRun.defer(10, _this);
16551             } 
16552             
16553             
16554             msg = "Building Interface " + (total  - mods.length) + 
16555                     " of " + total + 
16556                     (m.name ? (' - ' + m.name) : '');
16557                         Roo.debug && Roo.log(msg);
16558             if (!_this.hideProgress &&  Roo.MessageBox) { 
16559                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16560             }
16561             
16562          
16563             // is the module disabled?
16564             var disabled = (typeof(m.disabled) == 'function') ?
16565                 m.disabled.call(m.module.disabled) : m.disabled;    
16566             
16567             
16568             if (disabled) {
16569                 return progressRun(); // we do not update the display!
16570             }
16571             
16572             // now build 
16573             
16574                         
16575                         
16576             m.render();
16577             // it's 10 on top level, and 1 on others??? why...
16578             return progressRun.defer(10, _this);
16579              
16580         }
16581         progressRun.defer(1, _this);
16582      
16583         
16584         
16585     },
16586         
16587         
16588         /**
16589          * Event Object.
16590          *
16591          *
16592          */
16593         event: false, 
16594     /**
16595          * wrapper for event.on - aliased later..  
16596          * Typically use to register a event handler for register:
16597          *
16598          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16599          *
16600          */
16601     on : false
16602    
16603     
16604     
16605 });
16606
16607 Roo.XComponent.event = new Roo.util.Observable({
16608                 events : { 
16609                         /**
16610                          * @event register
16611                          * Fires when an Component is registered,
16612                          * set the disable property on the Component to stop registration.
16613                          * @param {Roo.XComponent} c the component being registerd.
16614                          * 
16615                          */
16616                         'register' : true,
16617             /**
16618                          * @event beforebuild
16619                          * Fires before each Component is built
16620                          * can be used to apply permissions.
16621                          * @param {Roo.XComponent} c the component being registerd.
16622                          * 
16623                          */
16624                         'beforebuild' : true,
16625                         /**
16626                          * @event buildcomplete
16627                          * Fires on the top level element when all elements have been built
16628                          * @param {Roo.XComponent} the top level component.
16629                          */
16630                         'buildcomplete' : true
16631                         
16632                 }
16633 });
16634
16635 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16636  //
16637  /**
16638  * marked - a markdown parser
16639  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16640  * https://github.com/chjj/marked
16641  */
16642
16643
16644 /**
16645  *
16646  * Roo.Markdown - is a very crude wrapper around marked..
16647  *
16648  * usage:
16649  * 
16650  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16651  * 
16652  * Note: move the sample code to the bottom of this
16653  * file before uncommenting it.
16654  *
16655  */
16656
16657 Roo.Markdown = {};
16658 Roo.Markdown.toHtml = function(text) {
16659     
16660     var c = new Roo.Markdown.marked.setOptions({
16661             renderer: new Roo.Markdown.marked.Renderer(),
16662             gfm: true,
16663             tables: true,
16664             breaks: false,
16665             pedantic: false,
16666             sanitize: false,
16667             smartLists: true,
16668             smartypants: false
16669           });
16670     // A FEW HACKS!!?
16671     
16672     text = text.replace(/\\\n/g,' ');
16673     return Roo.Markdown.marked(text);
16674 };
16675 //
16676 // converter
16677 //
16678 // Wraps all "globals" so that the only thing
16679 // exposed is makeHtml().
16680 //
16681 (function() {
16682     
16683     /**
16684      * Block-Level Grammar
16685      */
16686     
16687     var block = {
16688       newline: /^\n+/,
16689       code: /^( {4}[^\n]+\n*)+/,
16690       fences: noop,
16691       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16692       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16693       nptable: noop,
16694       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16695       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16696       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16697       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16698       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16699       table: noop,
16700       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16701       text: /^[^\n]+/
16702     };
16703     
16704     block.bullet = /(?:[*+-]|\d+\.)/;
16705     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16706     block.item = replace(block.item, 'gm')
16707       (/bull/g, block.bullet)
16708       ();
16709     
16710     block.list = replace(block.list)
16711       (/bull/g, block.bullet)
16712       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16713       ('def', '\\n+(?=' + block.def.source + ')')
16714       ();
16715     
16716     block.blockquote = replace(block.blockquote)
16717       ('def', block.def)
16718       ();
16719     
16720     block._tag = '(?!(?:'
16721       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16722       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16723       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16724     
16725     block.html = replace(block.html)
16726       ('comment', /<!--[\s\S]*?-->/)
16727       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16728       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16729       (/tag/g, block._tag)
16730       ();
16731     
16732     block.paragraph = replace(block.paragraph)
16733       ('hr', block.hr)
16734       ('heading', block.heading)
16735       ('lheading', block.lheading)
16736       ('blockquote', block.blockquote)
16737       ('tag', '<' + block._tag)
16738       ('def', block.def)
16739       ();
16740     
16741     /**
16742      * Normal Block Grammar
16743      */
16744     
16745     block.normal = merge({}, block);
16746     
16747     /**
16748      * GFM Block Grammar
16749      */
16750     
16751     block.gfm = merge({}, block.normal, {
16752       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16753       paragraph: /^/,
16754       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16755     });
16756     
16757     block.gfm.paragraph = replace(block.paragraph)
16758       ('(?!', '(?!'
16759         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16760         + block.list.source.replace('\\1', '\\3') + '|')
16761       ();
16762     
16763     /**
16764      * GFM + Tables Block Grammar
16765      */
16766     
16767     block.tables = merge({}, block.gfm, {
16768       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16769       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16770     });
16771     
16772     /**
16773      * Block Lexer
16774      */
16775     
16776     function Lexer(options) {
16777       this.tokens = [];
16778       this.tokens.links = {};
16779       this.options = options || marked.defaults;
16780       this.rules = block.normal;
16781     
16782       if (this.options.gfm) {
16783         if (this.options.tables) {
16784           this.rules = block.tables;
16785         } else {
16786           this.rules = block.gfm;
16787         }
16788       }
16789     }
16790     
16791     /**
16792      * Expose Block Rules
16793      */
16794     
16795     Lexer.rules = block;
16796     
16797     /**
16798      * Static Lex Method
16799      */
16800     
16801     Lexer.lex = function(src, options) {
16802       var lexer = new Lexer(options);
16803       return lexer.lex(src);
16804     };
16805     
16806     /**
16807      * Preprocessing
16808      */
16809     
16810     Lexer.prototype.lex = function(src) {
16811       src = src
16812         .replace(/\r\n|\r/g, '\n')
16813         .replace(/\t/g, '    ')
16814         .replace(/\u00a0/g, ' ')
16815         .replace(/\u2424/g, '\n');
16816     
16817       return this.token(src, true);
16818     };
16819     
16820     /**
16821      * Lexing
16822      */
16823     
16824     Lexer.prototype.token = function(src, top, bq) {
16825       var src = src.replace(/^ +$/gm, '')
16826         , next
16827         , loose
16828         , cap
16829         , bull
16830         , b
16831         , item
16832         , space
16833         , i
16834         , l;
16835     
16836       while (src) {
16837         // newline
16838         if (cap = this.rules.newline.exec(src)) {
16839           src = src.substring(cap[0].length);
16840           if (cap[0].length > 1) {
16841             this.tokens.push({
16842               type: 'space'
16843             });
16844           }
16845         }
16846     
16847         // code
16848         if (cap = this.rules.code.exec(src)) {
16849           src = src.substring(cap[0].length);
16850           cap = cap[0].replace(/^ {4}/gm, '');
16851           this.tokens.push({
16852             type: 'code',
16853             text: !this.options.pedantic
16854               ? cap.replace(/\n+$/, '')
16855               : cap
16856           });
16857           continue;
16858         }
16859     
16860         // fences (gfm)
16861         if (cap = this.rules.fences.exec(src)) {
16862           src = src.substring(cap[0].length);
16863           this.tokens.push({
16864             type: 'code',
16865             lang: cap[2],
16866             text: cap[3] || ''
16867           });
16868           continue;
16869         }
16870     
16871         // heading
16872         if (cap = this.rules.heading.exec(src)) {
16873           src = src.substring(cap[0].length);
16874           this.tokens.push({
16875             type: 'heading',
16876             depth: cap[1].length,
16877             text: cap[2]
16878           });
16879           continue;
16880         }
16881     
16882         // table no leading pipe (gfm)
16883         if (top && (cap = this.rules.nptable.exec(src))) {
16884           src = src.substring(cap[0].length);
16885     
16886           item = {
16887             type: 'table',
16888             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16889             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16890             cells: cap[3].replace(/\n$/, '').split('\n')
16891           };
16892     
16893           for (i = 0; i < item.align.length; i++) {
16894             if (/^ *-+: *$/.test(item.align[i])) {
16895               item.align[i] = 'right';
16896             } else if (/^ *:-+: *$/.test(item.align[i])) {
16897               item.align[i] = 'center';
16898             } else if (/^ *:-+ *$/.test(item.align[i])) {
16899               item.align[i] = 'left';
16900             } else {
16901               item.align[i] = null;
16902             }
16903           }
16904     
16905           for (i = 0; i < item.cells.length; i++) {
16906             item.cells[i] = item.cells[i].split(/ *\| */);
16907           }
16908     
16909           this.tokens.push(item);
16910     
16911           continue;
16912         }
16913     
16914         // lheading
16915         if (cap = this.rules.lheading.exec(src)) {
16916           src = src.substring(cap[0].length);
16917           this.tokens.push({
16918             type: 'heading',
16919             depth: cap[2] === '=' ? 1 : 2,
16920             text: cap[1]
16921           });
16922           continue;
16923         }
16924     
16925         // hr
16926         if (cap = this.rules.hr.exec(src)) {
16927           src = src.substring(cap[0].length);
16928           this.tokens.push({
16929             type: 'hr'
16930           });
16931           continue;
16932         }
16933     
16934         // blockquote
16935         if (cap = this.rules.blockquote.exec(src)) {
16936           src = src.substring(cap[0].length);
16937     
16938           this.tokens.push({
16939             type: 'blockquote_start'
16940           });
16941     
16942           cap = cap[0].replace(/^ *> ?/gm, '');
16943     
16944           // Pass `top` to keep the current
16945           // "toplevel" state. This is exactly
16946           // how markdown.pl works.
16947           this.token(cap, top, true);
16948     
16949           this.tokens.push({
16950             type: 'blockquote_end'
16951           });
16952     
16953           continue;
16954         }
16955     
16956         // list
16957         if (cap = this.rules.list.exec(src)) {
16958           src = src.substring(cap[0].length);
16959           bull = cap[2];
16960     
16961           this.tokens.push({
16962             type: 'list_start',
16963             ordered: bull.length > 1
16964           });
16965     
16966           // Get each top-level item.
16967           cap = cap[0].match(this.rules.item);
16968     
16969           next = false;
16970           l = cap.length;
16971           i = 0;
16972     
16973           for (; i < l; i++) {
16974             item = cap[i];
16975     
16976             // Remove the list item's bullet
16977             // so it is seen as the next token.
16978             space = item.length;
16979             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16980     
16981             // Outdent whatever the
16982             // list item contains. Hacky.
16983             if (~item.indexOf('\n ')) {
16984               space -= item.length;
16985               item = !this.options.pedantic
16986                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16987                 : item.replace(/^ {1,4}/gm, '');
16988             }
16989     
16990             // Determine whether the next list item belongs here.
16991             // Backpedal if it does not belong in this list.
16992             if (this.options.smartLists && i !== l - 1) {
16993               b = block.bullet.exec(cap[i + 1])[0];
16994               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16995                 src = cap.slice(i + 1).join('\n') + src;
16996                 i = l - 1;
16997               }
16998             }
16999     
17000             // Determine whether item is loose or not.
17001             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17002             // for discount behavior.
17003             loose = next || /\n\n(?!\s*$)/.test(item);
17004             if (i !== l - 1) {
17005               next = item.charAt(item.length - 1) === '\n';
17006               if (!loose) { loose = next; }
17007             }
17008     
17009             this.tokens.push({
17010               type: loose
17011                 ? 'loose_item_start'
17012                 : 'list_item_start'
17013             });
17014     
17015             // Recurse.
17016             this.token(item, false, bq);
17017     
17018             this.tokens.push({
17019               type: 'list_item_end'
17020             });
17021           }
17022     
17023           this.tokens.push({
17024             type: 'list_end'
17025           });
17026     
17027           continue;
17028         }
17029     
17030         // html
17031         if (cap = this.rules.html.exec(src)) {
17032           src = src.substring(cap[0].length);
17033           this.tokens.push({
17034             type: this.options.sanitize
17035               ? 'paragraph'
17036               : 'html',
17037             pre: !this.options.sanitizer
17038               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17039             text: cap[0]
17040           });
17041           continue;
17042         }
17043     
17044         // def
17045         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17046           src = src.substring(cap[0].length);
17047           this.tokens.links[cap[1].toLowerCase()] = {
17048             href: cap[2],
17049             title: cap[3]
17050           };
17051           continue;
17052         }
17053     
17054         // table (gfm)
17055         if (top && (cap = this.rules.table.exec(src))) {
17056           src = src.substring(cap[0].length);
17057     
17058           item = {
17059             type: 'table',
17060             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17061             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17062             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17063           };
17064     
17065           for (i = 0; i < item.align.length; i++) {
17066             if (/^ *-+: *$/.test(item.align[i])) {
17067               item.align[i] = 'right';
17068             } else if (/^ *:-+: *$/.test(item.align[i])) {
17069               item.align[i] = 'center';
17070             } else if (/^ *:-+ *$/.test(item.align[i])) {
17071               item.align[i] = 'left';
17072             } else {
17073               item.align[i] = null;
17074             }
17075           }
17076     
17077           for (i = 0; i < item.cells.length; i++) {
17078             item.cells[i] = item.cells[i]
17079               .replace(/^ *\| *| *\| *$/g, '')
17080               .split(/ *\| */);
17081           }
17082     
17083           this.tokens.push(item);
17084     
17085           continue;
17086         }
17087     
17088         // top-level paragraph
17089         if (top && (cap = this.rules.paragraph.exec(src))) {
17090           src = src.substring(cap[0].length);
17091           this.tokens.push({
17092             type: 'paragraph',
17093             text: cap[1].charAt(cap[1].length - 1) === '\n'
17094               ? cap[1].slice(0, -1)
17095               : cap[1]
17096           });
17097           continue;
17098         }
17099     
17100         // text
17101         if (cap = this.rules.text.exec(src)) {
17102           // Top-level should never reach here.
17103           src = src.substring(cap[0].length);
17104           this.tokens.push({
17105             type: 'text',
17106             text: cap[0]
17107           });
17108           continue;
17109         }
17110     
17111         if (src) {
17112           throw new
17113             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17114         }
17115       }
17116     
17117       return this.tokens;
17118     };
17119     
17120     /**
17121      * Inline-Level Grammar
17122      */
17123     
17124     var inline = {
17125       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17126       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17127       url: noop,
17128       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17129       link: /^!?\[(inside)\]\(href\)/,
17130       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17131       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17132       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17133       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17134       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17135       br: /^ {2,}\n(?!\s*$)/,
17136       del: noop,
17137       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17138     };
17139     
17140     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17141     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17142     
17143     inline.link = replace(inline.link)
17144       ('inside', inline._inside)
17145       ('href', inline._href)
17146       ();
17147     
17148     inline.reflink = replace(inline.reflink)
17149       ('inside', inline._inside)
17150       ();
17151     
17152     /**
17153      * Normal Inline Grammar
17154      */
17155     
17156     inline.normal = merge({}, inline);
17157     
17158     /**
17159      * Pedantic Inline Grammar
17160      */
17161     
17162     inline.pedantic = merge({}, inline.normal, {
17163       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17164       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17165     });
17166     
17167     /**
17168      * GFM Inline Grammar
17169      */
17170     
17171     inline.gfm = merge({}, inline.normal, {
17172       escape: replace(inline.escape)('])', '~|])')(),
17173       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17174       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17175       text: replace(inline.text)
17176         (']|', '~]|')
17177         ('|', '|https?://|')
17178         ()
17179     });
17180     
17181     /**
17182      * GFM + Line Breaks Inline Grammar
17183      */
17184     
17185     inline.breaks = merge({}, inline.gfm, {
17186       br: replace(inline.br)('{2,}', '*')(),
17187       text: replace(inline.gfm.text)('{2,}', '*')()
17188     });
17189     
17190     /**
17191      * Inline Lexer & Compiler
17192      */
17193     
17194     function InlineLexer(links, options) {
17195       this.options = options || marked.defaults;
17196       this.links = links;
17197       this.rules = inline.normal;
17198       this.renderer = this.options.renderer || new Renderer;
17199       this.renderer.options = this.options;
17200     
17201       if (!this.links) {
17202         throw new
17203           Error('Tokens array requires a `links` property.');
17204       }
17205     
17206       if (this.options.gfm) {
17207         if (this.options.breaks) {
17208           this.rules = inline.breaks;
17209         } else {
17210           this.rules = inline.gfm;
17211         }
17212       } else if (this.options.pedantic) {
17213         this.rules = inline.pedantic;
17214       }
17215     }
17216     
17217     /**
17218      * Expose Inline Rules
17219      */
17220     
17221     InlineLexer.rules = inline;
17222     
17223     /**
17224      * Static Lexing/Compiling Method
17225      */
17226     
17227     InlineLexer.output = function(src, links, options) {
17228       var inline = new InlineLexer(links, options);
17229       return inline.output(src);
17230     };
17231     
17232     /**
17233      * Lexing/Compiling
17234      */
17235     
17236     InlineLexer.prototype.output = function(src) {
17237       var out = ''
17238         , link
17239         , text
17240         , href
17241         , cap;
17242     
17243       while (src) {
17244         // escape
17245         if (cap = this.rules.escape.exec(src)) {
17246           src = src.substring(cap[0].length);
17247           out += cap[1];
17248           continue;
17249         }
17250     
17251         // autolink
17252         if (cap = this.rules.autolink.exec(src)) {
17253           src = src.substring(cap[0].length);
17254           if (cap[2] === '@') {
17255             text = cap[1].charAt(6) === ':'
17256               ? this.mangle(cap[1].substring(7))
17257               : this.mangle(cap[1]);
17258             href = this.mangle('mailto:') + text;
17259           } else {
17260             text = escape(cap[1]);
17261             href = text;
17262           }
17263           out += this.renderer.link(href, null, text);
17264           continue;
17265         }
17266     
17267         // url (gfm)
17268         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17269           src = src.substring(cap[0].length);
17270           text = escape(cap[1]);
17271           href = text;
17272           out += this.renderer.link(href, null, text);
17273           continue;
17274         }
17275     
17276         // tag
17277         if (cap = this.rules.tag.exec(src)) {
17278           if (!this.inLink && /^<a /i.test(cap[0])) {
17279             this.inLink = true;
17280           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17281             this.inLink = false;
17282           }
17283           src = src.substring(cap[0].length);
17284           out += this.options.sanitize
17285             ? this.options.sanitizer
17286               ? this.options.sanitizer(cap[0])
17287               : escape(cap[0])
17288             : cap[0];
17289           continue;
17290         }
17291     
17292         // link
17293         if (cap = this.rules.link.exec(src)) {
17294           src = src.substring(cap[0].length);
17295           this.inLink = true;
17296           out += this.outputLink(cap, {
17297             href: cap[2],
17298             title: cap[3]
17299           });
17300           this.inLink = false;
17301           continue;
17302         }
17303     
17304         // reflink, nolink
17305         if ((cap = this.rules.reflink.exec(src))
17306             || (cap = this.rules.nolink.exec(src))) {
17307           src = src.substring(cap[0].length);
17308           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17309           link = this.links[link.toLowerCase()];
17310           if (!link || !link.href) {
17311             out += cap[0].charAt(0);
17312             src = cap[0].substring(1) + src;
17313             continue;
17314           }
17315           this.inLink = true;
17316           out += this.outputLink(cap, link);
17317           this.inLink = false;
17318           continue;
17319         }
17320     
17321         // strong
17322         if (cap = this.rules.strong.exec(src)) {
17323           src = src.substring(cap[0].length);
17324           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17325           continue;
17326         }
17327     
17328         // em
17329         if (cap = this.rules.em.exec(src)) {
17330           src = src.substring(cap[0].length);
17331           out += this.renderer.em(this.output(cap[2] || cap[1]));
17332           continue;
17333         }
17334     
17335         // code
17336         if (cap = this.rules.code.exec(src)) {
17337           src = src.substring(cap[0].length);
17338           out += this.renderer.codespan(escape(cap[2], true));
17339           continue;
17340         }
17341     
17342         // br
17343         if (cap = this.rules.br.exec(src)) {
17344           src = src.substring(cap[0].length);
17345           out += this.renderer.br();
17346           continue;
17347         }
17348     
17349         // del (gfm)
17350         if (cap = this.rules.del.exec(src)) {
17351           src = src.substring(cap[0].length);
17352           out += this.renderer.del(this.output(cap[1]));
17353           continue;
17354         }
17355     
17356         // text
17357         if (cap = this.rules.text.exec(src)) {
17358           src = src.substring(cap[0].length);
17359           out += this.renderer.text(escape(this.smartypants(cap[0])));
17360           continue;
17361         }
17362     
17363         if (src) {
17364           throw new
17365             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17366         }
17367       }
17368     
17369       return out;
17370     };
17371     
17372     /**
17373      * Compile Link
17374      */
17375     
17376     InlineLexer.prototype.outputLink = function(cap, link) {
17377       var href = escape(link.href)
17378         , title = link.title ? escape(link.title) : null;
17379     
17380       return cap[0].charAt(0) !== '!'
17381         ? this.renderer.link(href, title, this.output(cap[1]))
17382         : this.renderer.image(href, title, escape(cap[1]));
17383     };
17384     
17385     /**
17386      * Smartypants Transformations
17387      */
17388     
17389     InlineLexer.prototype.smartypants = function(text) {
17390       if (!this.options.smartypants)  { return text; }
17391       return text
17392         // em-dashes
17393         .replace(/---/g, '\u2014')
17394         // en-dashes
17395         .replace(/--/g, '\u2013')
17396         // opening singles
17397         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17398         // closing singles & apostrophes
17399         .replace(/'/g, '\u2019')
17400         // opening doubles
17401         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17402         // closing doubles
17403         .replace(/"/g, '\u201d')
17404         // ellipses
17405         .replace(/\.{3}/g, '\u2026');
17406     };
17407     
17408     /**
17409      * Mangle Links
17410      */
17411     
17412     InlineLexer.prototype.mangle = function(text) {
17413       if (!this.options.mangle) { return text; }
17414       var out = ''
17415         , l = text.length
17416         , i = 0
17417         , ch;
17418     
17419       for (; i < l; i++) {
17420         ch = text.charCodeAt(i);
17421         if (Math.random() > 0.5) {
17422           ch = 'x' + ch.toString(16);
17423         }
17424         out += '&#' + ch + ';';
17425       }
17426     
17427       return out;
17428     };
17429     
17430     /**
17431      * Renderer
17432      */
17433     
17434     function Renderer(options) {
17435       this.options = options || {};
17436     }
17437     
17438     Renderer.prototype.code = function(code, lang, escaped) {
17439       if (this.options.highlight) {
17440         var out = this.options.highlight(code, lang);
17441         if (out != null && out !== code) {
17442           escaped = true;
17443           code = out;
17444         }
17445       } else {
17446             // hack!!! - it's already escapeD?
17447             escaped = true;
17448       }
17449     
17450       if (!lang) {
17451         return '<pre><code>'
17452           + (escaped ? code : escape(code, true))
17453           + '\n</code></pre>';
17454       }
17455     
17456       return '<pre><code class="'
17457         + this.options.langPrefix
17458         + escape(lang, true)
17459         + '">'
17460         + (escaped ? code : escape(code, true))
17461         + '\n</code></pre>\n';
17462     };
17463     
17464     Renderer.prototype.blockquote = function(quote) {
17465       return '<blockquote>\n' + quote + '</blockquote>\n';
17466     };
17467     
17468     Renderer.prototype.html = function(html) {
17469       return html;
17470     };
17471     
17472     Renderer.prototype.heading = function(text, level, raw) {
17473       return '<h'
17474         + level
17475         + ' id="'
17476         + this.options.headerPrefix
17477         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17478         + '">'
17479         + text
17480         + '</h'
17481         + level
17482         + '>\n';
17483     };
17484     
17485     Renderer.prototype.hr = function() {
17486       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17487     };
17488     
17489     Renderer.prototype.list = function(body, ordered) {
17490       var type = ordered ? 'ol' : 'ul';
17491       return '<' + type + '>\n' + body + '</' + type + '>\n';
17492     };
17493     
17494     Renderer.prototype.listitem = function(text) {
17495       return '<li>' + text + '</li>\n';
17496     };
17497     
17498     Renderer.prototype.paragraph = function(text) {
17499       return '<p>' + text + '</p>\n';
17500     };
17501     
17502     Renderer.prototype.table = function(header, body) {
17503       return '<table class="table table-striped">\n'
17504         + '<thead>\n'
17505         + header
17506         + '</thead>\n'
17507         + '<tbody>\n'
17508         + body
17509         + '</tbody>\n'
17510         + '</table>\n';
17511     };
17512     
17513     Renderer.prototype.tablerow = function(content) {
17514       return '<tr>\n' + content + '</tr>\n';
17515     };
17516     
17517     Renderer.prototype.tablecell = function(content, flags) {
17518       var type = flags.header ? 'th' : 'td';
17519       var tag = flags.align
17520         ? '<' + type + ' style="text-align:' + flags.align + '">'
17521         : '<' + type + '>';
17522       return tag + content + '</' + type + '>\n';
17523     };
17524     
17525     // span level renderer
17526     Renderer.prototype.strong = function(text) {
17527       return '<strong>' + text + '</strong>';
17528     };
17529     
17530     Renderer.prototype.em = function(text) {
17531       return '<em>' + text + '</em>';
17532     };
17533     
17534     Renderer.prototype.codespan = function(text) {
17535       return '<code>' + text + '</code>';
17536     };
17537     
17538     Renderer.prototype.br = function() {
17539       return this.options.xhtml ? '<br/>' : '<br>';
17540     };
17541     
17542     Renderer.prototype.del = function(text) {
17543       return '<del>' + text + '</del>';
17544     };
17545     
17546     Renderer.prototype.link = function(href, title, text) {
17547       if (this.options.sanitize) {
17548         try {
17549           var prot = decodeURIComponent(unescape(href))
17550             .replace(/[^\w:]/g, '')
17551             .toLowerCase();
17552         } catch (e) {
17553           return '';
17554         }
17555         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17556           return '';
17557         }
17558       }
17559       var out = '<a href="' + href + '"';
17560       if (title) {
17561         out += ' title="' + title + '"';
17562       }
17563       out += '>' + text + '</a>';
17564       return out;
17565     };
17566     
17567     Renderer.prototype.image = function(href, title, text) {
17568       var out = '<img src="' + href + '" alt="' + text + '"';
17569       if (title) {
17570         out += ' title="' + title + '"';
17571       }
17572       out += this.options.xhtml ? '/>' : '>';
17573       return out;
17574     };
17575     
17576     Renderer.prototype.text = function(text) {
17577       return text;
17578     };
17579     
17580     /**
17581      * Parsing & Compiling
17582      */
17583     
17584     function Parser(options) {
17585       this.tokens = [];
17586       this.token = null;
17587       this.options = options || marked.defaults;
17588       this.options.renderer = this.options.renderer || new Renderer;
17589       this.renderer = this.options.renderer;
17590       this.renderer.options = this.options;
17591     }
17592     
17593     /**
17594      * Static Parse Method
17595      */
17596     
17597     Parser.parse = function(src, options, renderer) {
17598       var parser = new Parser(options, renderer);
17599       return parser.parse(src);
17600     };
17601     
17602     /**
17603      * Parse Loop
17604      */
17605     
17606     Parser.prototype.parse = function(src) {
17607       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17608       this.tokens = src.reverse();
17609     
17610       var out = '';
17611       while (this.next()) {
17612         out += this.tok();
17613       }
17614     
17615       return out;
17616     };
17617     
17618     /**
17619      * Next Token
17620      */
17621     
17622     Parser.prototype.next = function() {
17623       return this.token = this.tokens.pop();
17624     };
17625     
17626     /**
17627      * Preview Next Token
17628      */
17629     
17630     Parser.prototype.peek = function() {
17631       return this.tokens[this.tokens.length - 1] || 0;
17632     };
17633     
17634     /**
17635      * Parse Text Tokens
17636      */
17637     
17638     Parser.prototype.parseText = function() {
17639       var body = this.token.text;
17640     
17641       while (this.peek().type === 'text') {
17642         body += '\n' + this.next().text;
17643       }
17644     
17645       return this.inline.output(body);
17646     };
17647     
17648     /**
17649      * Parse Current Token
17650      */
17651     
17652     Parser.prototype.tok = function() {
17653       switch (this.token.type) {
17654         case 'space': {
17655           return '';
17656         }
17657         case 'hr': {
17658           return this.renderer.hr();
17659         }
17660         case 'heading': {
17661           return this.renderer.heading(
17662             this.inline.output(this.token.text),
17663             this.token.depth,
17664             this.token.text);
17665         }
17666         case 'code': {
17667           return this.renderer.code(this.token.text,
17668             this.token.lang,
17669             this.token.escaped);
17670         }
17671         case 'table': {
17672           var header = ''
17673             , body = ''
17674             , i
17675             , row
17676             , cell
17677             , flags
17678             , j;
17679     
17680           // header
17681           cell = '';
17682           for (i = 0; i < this.token.header.length; i++) {
17683             flags = { header: true, align: this.token.align[i] };
17684             cell += this.renderer.tablecell(
17685               this.inline.output(this.token.header[i]),
17686               { header: true, align: this.token.align[i] }
17687             );
17688           }
17689           header += this.renderer.tablerow(cell);
17690     
17691           for (i = 0; i < this.token.cells.length; i++) {
17692             row = this.token.cells[i];
17693     
17694             cell = '';
17695             for (j = 0; j < row.length; j++) {
17696               cell += this.renderer.tablecell(
17697                 this.inline.output(row[j]),
17698                 { header: false, align: this.token.align[j] }
17699               );
17700             }
17701     
17702             body += this.renderer.tablerow(cell);
17703           }
17704           return this.renderer.table(header, body);
17705         }
17706         case 'blockquote_start': {
17707           var body = '';
17708     
17709           while (this.next().type !== 'blockquote_end') {
17710             body += this.tok();
17711           }
17712     
17713           return this.renderer.blockquote(body);
17714         }
17715         case 'list_start': {
17716           var body = ''
17717             , ordered = this.token.ordered;
17718     
17719           while (this.next().type !== 'list_end') {
17720             body += this.tok();
17721           }
17722     
17723           return this.renderer.list(body, ordered);
17724         }
17725         case 'list_item_start': {
17726           var body = '';
17727     
17728           while (this.next().type !== 'list_item_end') {
17729             body += this.token.type === 'text'
17730               ? this.parseText()
17731               : this.tok();
17732           }
17733     
17734           return this.renderer.listitem(body);
17735         }
17736         case 'loose_item_start': {
17737           var body = '';
17738     
17739           while (this.next().type !== 'list_item_end') {
17740             body += this.tok();
17741           }
17742     
17743           return this.renderer.listitem(body);
17744         }
17745         case 'html': {
17746           var html = !this.token.pre && !this.options.pedantic
17747             ? this.inline.output(this.token.text)
17748             : this.token.text;
17749           return this.renderer.html(html);
17750         }
17751         case 'paragraph': {
17752           return this.renderer.paragraph(this.inline.output(this.token.text));
17753         }
17754         case 'text': {
17755           return this.renderer.paragraph(this.parseText());
17756         }
17757       }
17758     };
17759     
17760     /**
17761      * Helpers
17762      */
17763     
17764     function escape(html, encode) {
17765       return html
17766         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17767         .replace(/</g, '&lt;')
17768         .replace(/>/g, '&gt;')
17769         .replace(/"/g, '&quot;')
17770         .replace(/'/g, '&#39;');
17771     }
17772     
17773     function unescape(html) {
17774         // explicitly match decimal, hex, and named HTML entities 
17775       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17776         n = n.toLowerCase();
17777         if (n === 'colon') { return ':'; }
17778         if (n.charAt(0) === '#') {
17779           return n.charAt(1) === 'x'
17780             ? String.fromCharCode(parseInt(n.substring(2), 16))
17781             : String.fromCharCode(+n.substring(1));
17782         }
17783         return '';
17784       });
17785     }
17786     
17787     function replace(regex, opt) {
17788       regex = regex.source;
17789       opt = opt || '';
17790       return function self(name, val) {
17791         if (!name) { return new RegExp(regex, opt); }
17792         val = val.source || val;
17793         val = val.replace(/(^|[^\[])\^/g, '$1');
17794         regex = regex.replace(name, val);
17795         return self;
17796       };
17797     }
17798     
17799     function noop() {}
17800     noop.exec = noop;
17801     
17802     function merge(obj) {
17803       var i = 1
17804         , target
17805         , key;
17806     
17807       for (; i < arguments.length; i++) {
17808         target = arguments[i];
17809         for (key in target) {
17810           if (Object.prototype.hasOwnProperty.call(target, key)) {
17811             obj[key] = target[key];
17812           }
17813         }
17814       }
17815     
17816       return obj;
17817     }
17818     
17819     
17820     /**
17821      * Marked
17822      */
17823     
17824     function marked(src, opt, callback) {
17825       if (callback || typeof opt === 'function') {
17826         if (!callback) {
17827           callback = opt;
17828           opt = null;
17829         }
17830     
17831         opt = merge({}, marked.defaults, opt || {});
17832     
17833         var highlight = opt.highlight
17834           , tokens
17835           , pending
17836           , i = 0;
17837     
17838         try {
17839           tokens = Lexer.lex(src, opt)
17840         } catch (e) {
17841           return callback(e);
17842         }
17843     
17844         pending = tokens.length;
17845     
17846         var done = function(err) {
17847           if (err) {
17848             opt.highlight = highlight;
17849             return callback(err);
17850           }
17851     
17852           var out;
17853     
17854           try {
17855             out = Parser.parse(tokens, opt);
17856           } catch (e) {
17857             err = e;
17858           }
17859     
17860           opt.highlight = highlight;
17861     
17862           return err
17863             ? callback(err)
17864             : callback(null, out);
17865         };
17866     
17867         if (!highlight || highlight.length < 3) {
17868           return done();
17869         }
17870     
17871         delete opt.highlight;
17872     
17873         if (!pending) { return done(); }
17874     
17875         for (; i < tokens.length; i++) {
17876           (function(token) {
17877             if (token.type !== 'code') {
17878               return --pending || done();
17879             }
17880             return highlight(token.text, token.lang, function(err, code) {
17881               if (err) { return done(err); }
17882               if (code == null || code === token.text) {
17883                 return --pending || done();
17884               }
17885               token.text = code;
17886               token.escaped = true;
17887               --pending || done();
17888             });
17889           })(tokens[i]);
17890         }
17891     
17892         return;
17893       }
17894       try {
17895         if (opt) { opt = merge({}, marked.defaults, opt); }
17896         return Parser.parse(Lexer.lex(src, opt), opt);
17897       } catch (e) {
17898         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17899         if ((opt || marked.defaults).silent) {
17900           return '<p>An error occured:</p><pre>'
17901             + escape(e.message + '', true)
17902             + '</pre>';
17903         }
17904         throw e;
17905       }
17906     }
17907     
17908     /**
17909      * Options
17910      */
17911     
17912     marked.options =
17913     marked.setOptions = function(opt) {
17914       merge(marked.defaults, opt);
17915       return marked;
17916     };
17917     
17918     marked.defaults = {
17919       gfm: true,
17920       tables: true,
17921       breaks: false,
17922       pedantic: false,
17923       sanitize: false,
17924       sanitizer: null,
17925       mangle: true,
17926       smartLists: false,
17927       silent: false,
17928       highlight: null,
17929       langPrefix: 'lang-',
17930       smartypants: false,
17931       headerPrefix: '',
17932       renderer: new Renderer,
17933       xhtml: false
17934     };
17935     
17936     /**
17937      * Expose
17938      */
17939     
17940     marked.Parser = Parser;
17941     marked.parser = Parser.parse;
17942     
17943     marked.Renderer = Renderer;
17944     
17945     marked.Lexer = Lexer;
17946     marked.lexer = Lexer.lex;
17947     
17948     marked.InlineLexer = InlineLexer;
17949     marked.inlineLexer = InlineLexer.output;
17950     
17951     marked.parse = marked;
17952     
17953     Roo.Markdown.marked = marked;
17954
17955 })();/*
17956  * Based on:
17957  * Ext JS Library 1.1.1
17958  * Copyright(c) 2006-2007, Ext JS, LLC.
17959  *
17960  * Originally Released Under LGPL - original licence link has changed is not relivant.
17961  *
17962  * Fork - LGPL
17963  * <script type="text/javascript">
17964  */
17965
17966
17967
17968 /*
17969  * These classes are derivatives of the similarly named classes in the YUI Library.
17970  * The original license:
17971  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17972  * Code licensed under the BSD License:
17973  * http://developer.yahoo.net/yui/license.txt
17974  */
17975
17976 (function() {
17977
17978 var Event=Roo.EventManager;
17979 var Dom=Roo.lib.Dom;
17980
17981 /**
17982  * @class Roo.dd.DragDrop
17983  * @extends Roo.util.Observable
17984  * Defines the interface and base operation of items that that can be
17985  * dragged or can be drop targets.  It was designed to be extended, overriding
17986  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17987  * Up to three html elements can be associated with a DragDrop instance:
17988  * <ul>
17989  * <li>linked element: the element that is passed into the constructor.
17990  * This is the element which defines the boundaries for interaction with
17991  * other DragDrop objects.</li>
17992  * <li>handle element(s): The drag operation only occurs if the element that
17993  * was clicked matches a handle element.  By default this is the linked
17994  * element, but there are times that you will want only a portion of the
17995  * linked element to initiate the drag operation, and the setHandleElId()
17996  * method provides a way to define this.</li>
17997  * <li>drag element: this represents the element that would be moved along
17998  * with the cursor during a drag operation.  By default, this is the linked
17999  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18000  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18001  * </li>
18002  * </ul>
18003  * This class should not be instantiated until the onload event to ensure that
18004  * the associated elements are available.
18005  * The following would define a DragDrop obj that would interact with any
18006  * other DragDrop obj in the "group1" group:
18007  * <pre>
18008  *  dd = new Roo.dd.DragDrop("div1", "group1");
18009  * </pre>
18010  * Since none of the event handlers have been implemented, nothing would
18011  * actually happen if you were to run the code above.  Normally you would
18012  * override this class or one of the default implementations, but you can
18013  * also override the methods you want on an instance of the class...
18014  * <pre>
18015  *  dd.onDragDrop = function(e, id) {
18016  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18017  *  }
18018  * </pre>
18019  * @constructor
18020  * @param {String} id of the element that is linked to this instance
18021  * @param {String} sGroup the group of related DragDrop objects
18022  * @param {object} config an object containing configurable attributes
18023  *                Valid properties for DragDrop:
18024  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18025  */
18026 Roo.dd.DragDrop = function(id, sGroup, config) {
18027     if (id) {
18028         this.init(id, sGroup, config);
18029     }
18030     
18031 };
18032
18033 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18034
18035     /**
18036      * The id of the element associated with this object.  This is what we
18037      * refer to as the "linked element" because the size and position of
18038      * this element is used to determine when the drag and drop objects have
18039      * interacted.
18040      * @property id
18041      * @type String
18042      */
18043     id: null,
18044
18045     /**
18046      * Configuration attributes passed into the constructor
18047      * @property config
18048      * @type object
18049      */
18050     config: null,
18051
18052     /**
18053      * The id of the element that will be dragged.  By default this is same
18054      * as the linked element , but could be changed to another element. Ex:
18055      * Roo.dd.DDProxy
18056      * @property dragElId
18057      * @type String
18058      * @private
18059      */
18060     dragElId: null,
18061
18062     /**
18063      * the id of the element that initiates the drag operation.  By default
18064      * this is the linked element, but could be changed to be a child of this
18065      * element.  This lets us do things like only starting the drag when the
18066      * header element within the linked html element is clicked.
18067      * @property handleElId
18068      * @type String
18069      * @private
18070      */
18071     handleElId: null,
18072
18073     /**
18074      * An associative array of HTML tags that will be ignored if clicked.
18075      * @property invalidHandleTypes
18076      * @type {string: string}
18077      */
18078     invalidHandleTypes: null,
18079
18080     /**
18081      * An associative array of ids for elements that will be ignored if clicked
18082      * @property invalidHandleIds
18083      * @type {string: string}
18084      */
18085     invalidHandleIds: null,
18086
18087     /**
18088      * An indexted array of css class names for elements that will be ignored
18089      * if clicked.
18090      * @property invalidHandleClasses
18091      * @type string[]
18092      */
18093     invalidHandleClasses: null,
18094
18095     /**
18096      * The linked element's absolute X position at the time the drag was
18097      * started
18098      * @property startPageX
18099      * @type int
18100      * @private
18101      */
18102     startPageX: 0,
18103
18104     /**
18105      * The linked element's absolute X position at the time the drag was
18106      * started
18107      * @property startPageY
18108      * @type int
18109      * @private
18110      */
18111     startPageY: 0,
18112
18113     /**
18114      * The group defines a logical collection of DragDrop objects that are
18115      * related.  Instances only get events when interacting with other
18116      * DragDrop object in the same group.  This lets us define multiple
18117      * groups using a single DragDrop subclass if we want.
18118      * @property groups
18119      * @type {string: string}
18120      */
18121     groups: null,
18122
18123     /**
18124      * Individual drag/drop instances can be locked.  This will prevent
18125      * onmousedown start drag.
18126      * @property locked
18127      * @type boolean
18128      * @private
18129      */
18130     locked: false,
18131
18132     /**
18133      * Lock this instance
18134      * @method lock
18135      */
18136     lock: function() { this.locked = true; },
18137
18138     /**
18139      * Unlock this instace
18140      * @method unlock
18141      */
18142     unlock: function() { this.locked = false; },
18143
18144     /**
18145      * By default, all insances can be a drop target.  This can be disabled by
18146      * setting isTarget to false.
18147      * @method isTarget
18148      * @type boolean
18149      */
18150     isTarget: true,
18151
18152     /**
18153      * The padding configured for this drag and drop object for calculating
18154      * the drop zone intersection with this object.
18155      * @method padding
18156      * @type int[]
18157      */
18158     padding: null,
18159
18160     /**
18161      * Cached reference to the linked element
18162      * @property _domRef
18163      * @private
18164      */
18165     _domRef: null,
18166
18167     /**
18168      * Internal typeof flag
18169      * @property __ygDragDrop
18170      * @private
18171      */
18172     __ygDragDrop: true,
18173
18174     /**
18175      * Set to true when horizontal contraints are applied
18176      * @property constrainX
18177      * @type boolean
18178      * @private
18179      */
18180     constrainX: false,
18181
18182     /**
18183      * Set to true when vertical contraints are applied
18184      * @property constrainY
18185      * @type boolean
18186      * @private
18187      */
18188     constrainY: false,
18189
18190     /**
18191      * The left constraint
18192      * @property minX
18193      * @type int
18194      * @private
18195      */
18196     minX: 0,
18197
18198     /**
18199      * The right constraint
18200      * @property maxX
18201      * @type int
18202      * @private
18203      */
18204     maxX: 0,
18205
18206     /**
18207      * The up constraint
18208      * @property minY
18209      * @type int
18210      * @type int
18211      * @private
18212      */
18213     minY: 0,
18214
18215     /**
18216      * The down constraint
18217      * @property maxY
18218      * @type int
18219      * @private
18220      */
18221     maxY: 0,
18222
18223     /**
18224      * Maintain offsets when we resetconstraints.  Set to true when you want
18225      * the position of the element relative to its parent to stay the same
18226      * when the page changes
18227      *
18228      * @property maintainOffset
18229      * @type boolean
18230      */
18231     maintainOffset: false,
18232
18233     /**
18234      * Array of pixel locations the element will snap to if we specified a
18235      * horizontal graduation/interval.  This array is generated automatically
18236      * when you define a tick interval.
18237      * @property xTicks
18238      * @type int[]
18239      */
18240     xTicks: null,
18241
18242     /**
18243      * Array of pixel locations the element will snap to if we specified a
18244      * vertical graduation/interval.  This array is generated automatically
18245      * when you define a tick interval.
18246      * @property yTicks
18247      * @type int[]
18248      */
18249     yTicks: null,
18250
18251     /**
18252      * By default the drag and drop instance will only respond to the primary
18253      * button click (left button for a right-handed mouse).  Set to true to
18254      * allow drag and drop to start with any mouse click that is propogated
18255      * by the browser
18256      * @property primaryButtonOnly
18257      * @type boolean
18258      */
18259     primaryButtonOnly: true,
18260
18261     /**
18262      * The availabe property is false until the linked dom element is accessible.
18263      * @property available
18264      * @type boolean
18265      */
18266     available: false,
18267
18268     /**
18269      * By default, drags can only be initiated if the mousedown occurs in the
18270      * region the linked element is.  This is done in part to work around a
18271      * bug in some browsers that mis-report the mousedown if the previous
18272      * mouseup happened outside of the window.  This property is set to true
18273      * if outer handles are defined.
18274      *
18275      * @property hasOuterHandles
18276      * @type boolean
18277      * @default false
18278      */
18279     hasOuterHandles: false,
18280
18281     /**
18282      * Code that executes immediately before the startDrag event
18283      * @method b4StartDrag
18284      * @private
18285      */
18286     b4StartDrag: function(x, y) { },
18287
18288     /**
18289      * Abstract method called after a drag/drop object is clicked
18290      * and the drag or mousedown time thresholds have beeen met.
18291      * @method startDrag
18292      * @param {int} X click location
18293      * @param {int} Y click location
18294      */
18295     startDrag: function(x, y) { /* override this */ },
18296
18297     /**
18298      * Code that executes immediately before the onDrag event
18299      * @method b4Drag
18300      * @private
18301      */
18302     b4Drag: function(e) { },
18303
18304     /**
18305      * Abstract method called during the onMouseMove event while dragging an
18306      * object.
18307      * @method onDrag
18308      * @param {Event} e the mousemove event
18309      */
18310     onDrag: function(e) { /* override this */ },
18311
18312     /**
18313      * Abstract method called when this element fist begins hovering over
18314      * another DragDrop obj
18315      * @method onDragEnter
18316      * @param {Event} e the mousemove event
18317      * @param {String|DragDrop[]} id In POINT mode, the element
18318      * id this is hovering over.  In INTERSECT mode, an array of one or more
18319      * dragdrop items being hovered over.
18320      */
18321     onDragEnter: function(e, id) { /* override this */ },
18322
18323     /**
18324      * Code that executes immediately before the onDragOver event
18325      * @method b4DragOver
18326      * @private
18327      */
18328     b4DragOver: function(e) { },
18329
18330     /**
18331      * Abstract method called when this element is hovering over another
18332      * DragDrop obj
18333      * @method onDragOver
18334      * @param {Event} e the mousemove event
18335      * @param {String|DragDrop[]} id In POINT mode, the element
18336      * id this is hovering over.  In INTERSECT mode, an array of dd items
18337      * being hovered over.
18338      */
18339     onDragOver: function(e, id) { /* override this */ },
18340
18341     /**
18342      * Code that executes immediately before the onDragOut event
18343      * @method b4DragOut
18344      * @private
18345      */
18346     b4DragOut: function(e) { },
18347
18348     /**
18349      * Abstract method called when we are no longer hovering over an element
18350      * @method onDragOut
18351      * @param {Event} e the mousemove event
18352      * @param {String|DragDrop[]} id In POINT mode, the element
18353      * id this was hovering over.  In INTERSECT mode, an array of dd items
18354      * that the mouse is no longer over.
18355      */
18356     onDragOut: function(e, id) { /* override this */ },
18357
18358     /**
18359      * Code that executes immediately before the onDragDrop event
18360      * @method b4DragDrop
18361      * @private
18362      */
18363     b4DragDrop: function(e) { },
18364
18365     /**
18366      * Abstract method called when this item is dropped on another DragDrop
18367      * obj
18368      * @method onDragDrop
18369      * @param {Event} e the mouseup event
18370      * @param {String|DragDrop[]} id In POINT mode, the element
18371      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18372      * was dropped on.
18373      */
18374     onDragDrop: function(e, id) { /* override this */ },
18375
18376     /**
18377      * Abstract method called when this item is dropped on an area with no
18378      * drop target
18379      * @method onInvalidDrop
18380      * @param {Event} e the mouseup event
18381      */
18382     onInvalidDrop: function(e) { /* override this */ },
18383
18384     /**
18385      * Code that executes immediately before the endDrag event
18386      * @method b4EndDrag
18387      * @private
18388      */
18389     b4EndDrag: function(e) { },
18390
18391     /**
18392      * Fired when we are done dragging the object
18393      * @method endDrag
18394      * @param {Event} e the mouseup event
18395      */
18396     endDrag: function(e) { /* override this */ },
18397
18398     /**
18399      * Code executed immediately before the onMouseDown event
18400      * @method b4MouseDown
18401      * @param {Event} e the mousedown event
18402      * @private
18403      */
18404     b4MouseDown: function(e) {  },
18405
18406     /**
18407      * Event handler that fires when a drag/drop obj gets a mousedown
18408      * @method onMouseDown
18409      * @param {Event} e the mousedown event
18410      */
18411     onMouseDown: function(e) { /* override this */ },
18412
18413     /**
18414      * Event handler that fires when a drag/drop obj gets a mouseup
18415      * @method onMouseUp
18416      * @param {Event} e the mouseup event
18417      */
18418     onMouseUp: function(e) { /* override this */ },
18419
18420     /**
18421      * Override the onAvailable method to do what is needed after the initial
18422      * position was determined.
18423      * @method onAvailable
18424      */
18425     onAvailable: function () {
18426     },
18427
18428     /*
18429      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18430      * @type Object
18431      */
18432     defaultPadding : {left:0, right:0, top:0, bottom:0},
18433
18434     /*
18435      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18436  *
18437  * Usage:
18438  <pre><code>
18439  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18440                 { dragElId: "existingProxyDiv" });
18441  dd.startDrag = function(){
18442      this.constrainTo("parent-id");
18443  };
18444  </code></pre>
18445  * Or you can initalize it using the {@link Roo.Element} object:
18446  <pre><code>
18447  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18448      startDrag : function(){
18449          this.constrainTo("parent-id");
18450      }
18451  });
18452  </code></pre>
18453      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18454      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18455      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18456      * an object containing the sides to pad. For example: {right:10, bottom:10}
18457      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18458      */
18459     constrainTo : function(constrainTo, pad, inContent){
18460         if(typeof pad == "number"){
18461             pad = {left: pad, right:pad, top:pad, bottom:pad};
18462         }
18463         pad = pad || this.defaultPadding;
18464         var b = Roo.get(this.getEl()).getBox();
18465         var ce = Roo.get(constrainTo);
18466         var s = ce.getScroll();
18467         var c, cd = ce.dom;
18468         if(cd == document.body){
18469             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18470         }else{
18471             xy = ce.getXY();
18472             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18473         }
18474
18475
18476         var topSpace = b.y - c.y;
18477         var leftSpace = b.x - c.x;
18478
18479         this.resetConstraints();
18480         this.setXConstraint(leftSpace - (pad.left||0), // left
18481                 c.width - leftSpace - b.width - (pad.right||0) //right
18482         );
18483         this.setYConstraint(topSpace - (pad.top||0), //top
18484                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18485         );
18486     },
18487
18488     /**
18489      * Returns a reference to the linked element
18490      * @method getEl
18491      * @return {HTMLElement} the html element
18492      */
18493     getEl: function() {
18494         if (!this._domRef) {
18495             this._domRef = Roo.getDom(this.id);
18496         }
18497
18498         return this._domRef;
18499     },
18500
18501     /**
18502      * Returns a reference to the actual element to drag.  By default this is
18503      * the same as the html element, but it can be assigned to another
18504      * element. An example of this can be found in Roo.dd.DDProxy
18505      * @method getDragEl
18506      * @return {HTMLElement} the html element
18507      */
18508     getDragEl: function() {
18509         return Roo.getDom(this.dragElId);
18510     },
18511
18512     /**
18513      * Sets up the DragDrop object.  Must be called in the constructor of any
18514      * Roo.dd.DragDrop subclass
18515      * @method init
18516      * @param id the id of the linked element
18517      * @param {String} sGroup the group of related items
18518      * @param {object} config configuration attributes
18519      */
18520     init: function(id, sGroup, config) {
18521         this.initTarget(id, sGroup, config);
18522         if (!Roo.isTouch) {
18523             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18524         }
18525         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18526         // Event.on(this.id, "selectstart", Event.preventDefault);
18527     },
18528
18529     /**
18530      * Initializes Targeting functionality only... the object does not
18531      * get a mousedown handler.
18532      * @method initTarget
18533      * @param id the id of the linked element
18534      * @param {String} sGroup the group of related items
18535      * @param {object} config configuration attributes
18536      */
18537     initTarget: function(id, sGroup, config) {
18538
18539         // configuration attributes
18540         this.config = config || {};
18541
18542         // create a local reference to the drag and drop manager
18543         this.DDM = Roo.dd.DDM;
18544         // initialize the groups array
18545         this.groups = {};
18546
18547         // assume that we have an element reference instead of an id if the
18548         // parameter is not a string
18549         if (typeof id !== "string") {
18550             id = Roo.id(id);
18551         }
18552
18553         // set the id
18554         this.id = id;
18555
18556         // add to an interaction group
18557         this.addToGroup((sGroup) ? sGroup : "default");
18558
18559         // We don't want to register this as the handle with the manager
18560         // so we just set the id rather than calling the setter.
18561         this.handleElId = id;
18562
18563         // the linked element is the element that gets dragged by default
18564         this.setDragElId(id);
18565
18566         // by default, clicked anchors will not start drag operations.
18567         this.invalidHandleTypes = { A: "A" };
18568         this.invalidHandleIds = {};
18569         this.invalidHandleClasses = [];
18570
18571         this.applyConfig();
18572
18573         this.handleOnAvailable();
18574     },
18575
18576     /**
18577      * Applies the configuration parameters that were passed into the constructor.
18578      * This is supposed to happen at each level through the inheritance chain.  So
18579      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18580      * DragDrop in order to get all of the parameters that are available in
18581      * each object.
18582      * @method applyConfig
18583      */
18584     applyConfig: function() {
18585
18586         // configurable properties:
18587         //    padding, isTarget, maintainOffset, primaryButtonOnly
18588         this.padding           = this.config.padding || [0, 0, 0, 0];
18589         this.isTarget          = (this.config.isTarget !== false);
18590         this.maintainOffset    = (this.config.maintainOffset);
18591         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18592
18593     },
18594
18595     /**
18596      * Executed when the linked element is available
18597      * @method handleOnAvailable
18598      * @private
18599      */
18600     handleOnAvailable: function() {
18601         this.available = true;
18602         this.resetConstraints();
18603         this.onAvailable();
18604     },
18605
18606      /**
18607      * Configures the padding for the target zone in px.  Effectively expands
18608      * (or reduces) the virtual object size for targeting calculations.
18609      * Supports css-style shorthand; if only one parameter is passed, all sides
18610      * will have that padding, and if only two are passed, the top and bottom
18611      * will have the first param, the left and right the second.
18612      * @method setPadding
18613      * @param {int} iTop    Top pad
18614      * @param {int} iRight  Right pad
18615      * @param {int} iBot    Bot pad
18616      * @param {int} iLeft   Left pad
18617      */
18618     setPadding: function(iTop, iRight, iBot, iLeft) {
18619         // this.padding = [iLeft, iRight, iTop, iBot];
18620         if (!iRight && 0 !== iRight) {
18621             this.padding = [iTop, iTop, iTop, iTop];
18622         } else if (!iBot && 0 !== iBot) {
18623             this.padding = [iTop, iRight, iTop, iRight];
18624         } else {
18625             this.padding = [iTop, iRight, iBot, iLeft];
18626         }
18627     },
18628
18629     /**
18630      * Stores the initial placement of the linked element.
18631      * @method setInitialPosition
18632      * @param {int} diffX   the X offset, default 0
18633      * @param {int} diffY   the Y offset, default 0
18634      */
18635     setInitPosition: function(diffX, diffY) {
18636         var el = this.getEl();
18637
18638         if (!this.DDM.verifyEl(el)) {
18639             return;
18640         }
18641
18642         var dx = diffX || 0;
18643         var dy = diffY || 0;
18644
18645         var p = Dom.getXY( el );
18646
18647         this.initPageX = p[0] - dx;
18648         this.initPageY = p[1] - dy;
18649
18650         this.lastPageX = p[0];
18651         this.lastPageY = p[1];
18652
18653
18654         this.setStartPosition(p);
18655     },
18656
18657     /**
18658      * Sets the start position of the element.  This is set when the obj
18659      * is initialized, the reset when a drag is started.
18660      * @method setStartPosition
18661      * @param pos current position (from previous lookup)
18662      * @private
18663      */
18664     setStartPosition: function(pos) {
18665         var p = pos || Dom.getXY( this.getEl() );
18666         this.deltaSetXY = null;
18667
18668         this.startPageX = p[0];
18669         this.startPageY = p[1];
18670     },
18671
18672     /**
18673      * Add this instance to a group of related drag/drop objects.  All
18674      * instances belong to at least one group, and can belong to as many
18675      * groups as needed.
18676      * @method addToGroup
18677      * @param sGroup {string} the name of the group
18678      */
18679     addToGroup: function(sGroup) {
18680         this.groups[sGroup] = true;
18681         this.DDM.regDragDrop(this, sGroup);
18682     },
18683
18684     /**
18685      * Remove's this instance from the supplied interaction group
18686      * @method removeFromGroup
18687      * @param {string}  sGroup  The group to drop
18688      */
18689     removeFromGroup: function(sGroup) {
18690         if (this.groups[sGroup]) {
18691             delete this.groups[sGroup];
18692         }
18693
18694         this.DDM.removeDDFromGroup(this, sGroup);
18695     },
18696
18697     /**
18698      * Allows you to specify that an element other than the linked element
18699      * will be moved with the cursor during a drag
18700      * @method setDragElId
18701      * @param id {string} the id of the element that will be used to initiate the drag
18702      */
18703     setDragElId: function(id) {
18704         this.dragElId = id;
18705     },
18706
18707     /**
18708      * Allows you to specify a child of the linked element that should be
18709      * used to initiate the drag operation.  An example of this would be if
18710      * you have a content div with text and links.  Clicking anywhere in the
18711      * content area would normally start the drag operation.  Use this method
18712      * to specify that an element inside of the content div is the element
18713      * that starts the drag operation.
18714      * @method setHandleElId
18715      * @param id {string} the id of the element that will be used to
18716      * initiate the drag.
18717      */
18718     setHandleElId: function(id) {
18719         if (typeof id !== "string") {
18720             id = Roo.id(id);
18721         }
18722         this.handleElId = id;
18723         this.DDM.regHandle(this.id, id);
18724     },
18725
18726     /**
18727      * Allows you to set an element outside of the linked element as a drag
18728      * handle
18729      * @method setOuterHandleElId
18730      * @param id the id of the element that will be used to initiate the drag
18731      */
18732     setOuterHandleElId: function(id) {
18733         if (typeof id !== "string") {
18734             id = Roo.id(id);
18735         }
18736         Event.on(id, "mousedown",
18737                 this.handleMouseDown, this);
18738         this.setHandleElId(id);
18739
18740         this.hasOuterHandles = true;
18741     },
18742
18743     /**
18744      * Remove all drag and drop hooks for this element
18745      * @method unreg
18746      */
18747     unreg: function() {
18748         Event.un(this.id, "mousedown",
18749                 this.handleMouseDown);
18750         Event.un(this.id, "touchstart",
18751                 this.handleMouseDown);
18752         this._domRef = null;
18753         this.DDM._remove(this);
18754     },
18755
18756     destroy : function(){
18757         this.unreg();
18758     },
18759
18760     /**
18761      * Returns true if this instance is locked, or the drag drop mgr is locked
18762      * (meaning that all drag/drop is disabled on the page.)
18763      * @method isLocked
18764      * @return {boolean} true if this obj or all drag/drop is locked, else
18765      * false
18766      */
18767     isLocked: function() {
18768         return (this.DDM.isLocked() || this.locked);
18769     },
18770
18771     /**
18772      * Fired when this object is clicked
18773      * @method handleMouseDown
18774      * @param {Event} e
18775      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18776      * @private
18777      */
18778     handleMouseDown: function(e, oDD){
18779      
18780         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18781             //Roo.log('not touch/ button !=0');
18782             return;
18783         }
18784         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18785             return; // double touch..
18786         }
18787         
18788
18789         if (this.isLocked()) {
18790             //Roo.log('locked');
18791             return;
18792         }
18793
18794         this.DDM.refreshCache(this.groups);
18795 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18796         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18797         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18798             //Roo.log('no outer handes or not over target');
18799                 // do nothing.
18800         } else {
18801 //            Roo.log('check validator');
18802             if (this.clickValidator(e)) {
18803 //                Roo.log('validate success');
18804                 // set the initial element position
18805                 this.setStartPosition();
18806
18807
18808                 this.b4MouseDown(e);
18809                 this.onMouseDown(e);
18810
18811                 this.DDM.handleMouseDown(e, this);
18812
18813                 this.DDM.stopEvent(e);
18814             } else {
18815
18816
18817             }
18818         }
18819     },
18820
18821     clickValidator: function(e) {
18822         var target = e.getTarget();
18823         return ( this.isValidHandleChild(target) &&
18824                     (this.id == this.handleElId ||
18825                         this.DDM.handleWasClicked(target, this.id)) );
18826     },
18827
18828     /**
18829      * Allows you to specify a tag name that should not start a drag operation
18830      * when clicked.  This is designed to facilitate embedding links within a
18831      * drag handle that do something other than start the drag.
18832      * @method addInvalidHandleType
18833      * @param {string} tagName the type of element to exclude
18834      */
18835     addInvalidHandleType: function(tagName) {
18836         var type = tagName.toUpperCase();
18837         this.invalidHandleTypes[type] = type;
18838     },
18839
18840     /**
18841      * Lets you to specify an element id for a child of a drag handle
18842      * that should not initiate a drag
18843      * @method addInvalidHandleId
18844      * @param {string} id the element id of the element you wish to ignore
18845      */
18846     addInvalidHandleId: function(id) {
18847         if (typeof id !== "string") {
18848             id = Roo.id(id);
18849         }
18850         this.invalidHandleIds[id] = id;
18851     },
18852
18853     /**
18854      * Lets you specify a css class of elements that will not initiate a drag
18855      * @method addInvalidHandleClass
18856      * @param {string} cssClass the class of the elements you wish to ignore
18857      */
18858     addInvalidHandleClass: function(cssClass) {
18859         this.invalidHandleClasses.push(cssClass);
18860     },
18861
18862     /**
18863      * Unsets an excluded tag name set by addInvalidHandleType
18864      * @method removeInvalidHandleType
18865      * @param {string} tagName the type of element to unexclude
18866      */
18867     removeInvalidHandleType: function(tagName) {
18868         var type = tagName.toUpperCase();
18869         // this.invalidHandleTypes[type] = null;
18870         delete this.invalidHandleTypes[type];
18871     },
18872
18873     /**
18874      * Unsets an invalid handle id
18875      * @method removeInvalidHandleId
18876      * @param {string} id the id of the element to re-enable
18877      */
18878     removeInvalidHandleId: function(id) {
18879         if (typeof id !== "string") {
18880             id = Roo.id(id);
18881         }
18882         delete this.invalidHandleIds[id];
18883     },
18884
18885     /**
18886      * Unsets an invalid css class
18887      * @method removeInvalidHandleClass
18888      * @param {string} cssClass the class of the element(s) you wish to
18889      * re-enable
18890      */
18891     removeInvalidHandleClass: function(cssClass) {
18892         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18893             if (this.invalidHandleClasses[i] == cssClass) {
18894                 delete this.invalidHandleClasses[i];
18895             }
18896         }
18897     },
18898
18899     /**
18900      * Checks the tag exclusion list to see if this click should be ignored
18901      * @method isValidHandleChild
18902      * @param {HTMLElement} node the HTMLElement to evaluate
18903      * @return {boolean} true if this is a valid tag type, false if not
18904      */
18905     isValidHandleChild: function(node) {
18906
18907         var valid = true;
18908         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18909         var nodeName;
18910         try {
18911             nodeName = node.nodeName.toUpperCase();
18912         } catch(e) {
18913             nodeName = node.nodeName;
18914         }
18915         valid = valid && !this.invalidHandleTypes[nodeName];
18916         valid = valid && !this.invalidHandleIds[node.id];
18917
18918         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18919             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18920         }
18921
18922
18923         return valid;
18924
18925     },
18926
18927     /**
18928      * Create the array of horizontal tick marks if an interval was specified
18929      * in setXConstraint().
18930      * @method setXTicks
18931      * @private
18932      */
18933     setXTicks: function(iStartX, iTickSize) {
18934         this.xTicks = [];
18935         this.xTickSize = iTickSize;
18936
18937         var tickMap = {};
18938
18939         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18940             if (!tickMap[i]) {
18941                 this.xTicks[this.xTicks.length] = i;
18942                 tickMap[i] = true;
18943             }
18944         }
18945
18946         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18947             if (!tickMap[i]) {
18948                 this.xTicks[this.xTicks.length] = i;
18949                 tickMap[i] = true;
18950             }
18951         }
18952
18953         this.xTicks.sort(this.DDM.numericSort) ;
18954     },
18955
18956     /**
18957      * Create the array of vertical tick marks if an interval was specified in
18958      * setYConstraint().
18959      * @method setYTicks
18960      * @private
18961      */
18962     setYTicks: function(iStartY, iTickSize) {
18963         this.yTicks = [];
18964         this.yTickSize = iTickSize;
18965
18966         var tickMap = {};
18967
18968         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18969             if (!tickMap[i]) {
18970                 this.yTicks[this.yTicks.length] = i;
18971                 tickMap[i] = true;
18972             }
18973         }
18974
18975         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18976             if (!tickMap[i]) {
18977                 this.yTicks[this.yTicks.length] = i;
18978                 tickMap[i] = true;
18979             }
18980         }
18981
18982         this.yTicks.sort(this.DDM.numericSort) ;
18983     },
18984
18985     /**
18986      * By default, the element can be dragged any place on the screen.  Use
18987      * this method to limit the horizontal travel of the element.  Pass in
18988      * 0,0 for the parameters if you want to lock the drag to the y axis.
18989      * @method setXConstraint
18990      * @param {int} iLeft the number of pixels the element can move to the left
18991      * @param {int} iRight the number of pixels the element can move to the
18992      * right
18993      * @param {int} iTickSize optional parameter for specifying that the
18994      * element
18995      * should move iTickSize pixels at a time.
18996      */
18997     setXConstraint: function(iLeft, iRight, iTickSize) {
18998         this.leftConstraint = iLeft;
18999         this.rightConstraint = iRight;
19000
19001         this.minX = this.initPageX - iLeft;
19002         this.maxX = this.initPageX + iRight;
19003         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19004
19005         this.constrainX = true;
19006     },
19007
19008     /**
19009      * Clears any constraints applied to this instance.  Also clears ticks
19010      * since they can't exist independent of a constraint at this time.
19011      * @method clearConstraints
19012      */
19013     clearConstraints: function() {
19014         this.constrainX = false;
19015         this.constrainY = false;
19016         this.clearTicks();
19017     },
19018
19019     /**
19020      * Clears any tick interval defined for this instance
19021      * @method clearTicks
19022      */
19023     clearTicks: function() {
19024         this.xTicks = null;
19025         this.yTicks = null;
19026         this.xTickSize = 0;
19027         this.yTickSize = 0;
19028     },
19029
19030     /**
19031      * By default, the element can be dragged any place on the screen.  Set
19032      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19033      * parameters if you want to lock the drag to the x axis.
19034      * @method setYConstraint
19035      * @param {int} iUp the number of pixels the element can move up
19036      * @param {int} iDown the number of pixels the element can move down
19037      * @param {int} iTickSize optional parameter for specifying that the
19038      * element should move iTickSize pixels at a time.
19039      */
19040     setYConstraint: function(iUp, iDown, iTickSize) {
19041         this.topConstraint = iUp;
19042         this.bottomConstraint = iDown;
19043
19044         this.minY = this.initPageY - iUp;
19045         this.maxY = this.initPageY + iDown;
19046         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19047
19048         this.constrainY = true;
19049
19050     },
19051
19052     /**
19053      * resetConstraints must be called if you manually reposition a dd element.
19054      * @method resetConstraints
19055      * @param {boolean} maintainOffset
19056      */
19057     resetConstraints: function() {
19058
19059
19060         // Maintain offsets if necessary
19061         if (this.initPageX || this.initPageX === 0) {
19062             // figure out how much this thing has moved
19063             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19064             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19065
19066             this.setInitPosition(dx, dy);
19067
19068         // This is the first time we have detected the element's position
19069         } else {
19070             this.setInitPosition();
19071         }
19072
19073         if (this.constrainX) {
19074             this.setXConstraint( this.leftConstraint,
19075                                  this.rightConstraint,
19076                                  this.xTickSize        );
19077         }
19078
19079         if (this.constrainY) {
19080             this.setYConstraint( this.topConstraint,
19081                                  this.bottomConstraint,
19082                                  this.yTickSize         );
19083         }
19084     },
19085
19086     /**
19087      * Normally the drag element is moved pixel by pixel, but we can specify
19088      * that it move a number of pixels at a time.  This method resolves the
19089      * location when we have it set up like this.
19090      * @method getTick
19091      * @param {int} val where we want to place the object
19092      * @param {int[]} tickArray sorted array of valid points
19093      * @return {int} the closest tick
19094      * @private
19095      */
19096     getTick: function(val, tickArray) {
19097
19098         if (!tickArray) {
19099             // If tick interval is not defined, it is effectively 1 pixel,
19100             // so we return the value passed to us.
19101             return val;
19102         } else if (tickArray[0] >= val) {
19103             // The value is lower than the first tick, so we return the first
19104             // tick.
19105             return tickArray[0];
19106         } else {
19107             for (var i=0, len=tickArray.length; i<len; ++i) {
19108                 var next = i + 1;
19109                 if (tickArray[next] && tickArray[next] >= val) {
19110                     var diff1 = val - tickArray[i];
19111                     var diff2 = tickArray[next] - val;
19112                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19113                 }
19114             }
19115
19116             // The value is larger than the last tick, so we return the last
19117             // tick.
19118             return tickArray[tickArray.length - 1];
19119         }
19120     },
19121
19122     /**
19123      * toString method
19124      * @method toString
19125      * @return {string} string representation of the dd obj
19126      */
19127     toString: function() {
19128         return ("DragDrop " + this.id);
19129     }
19130
19131 });
19132
19133 })();
19134 /*
19135  * Based on:
19136  * Ext JS Library 1.1.1
19137  * Copyright(c) 2006-2007, Ext JS, LLC.
19138  *
19139  * Originally Released Under LGPL - original licence link has changed is not relivant.
19140  *
19141  * Fork - LGPL
19142  * <script type="text/javascript">
19143  */
19144
19145
19146 /**
19147  * The drag and drop utility provides a framework for building drag and drop
19148  * applications.  In addition to enabling drag and drop for specific elements,
19149  * the drag and drop elements are tracked by the manager class, and the
19150  * interactions between the various elements are tracked during the drag and
19151  * the implementing code is notified about these important moments.
19152  */
19153
19154 // Only load the library once.  Rewriting the manager class would orphan
19155 // existing drag and drop instances.
19156 if (!Roo.dd.DragDropMgr) {
19157
19158 /**
19159  * @class Roo.dd.DragDropMgr
19160  * DragDropMgr is a singleton that tracks the element interaction for
19161  * all DragDrop items in the window.  Generally, you will not call
19162  * this class directly, but it does have helper methods that could
19163  * be useful in your DragDrop implementations.
19164  * @singleton
19165  */
19166 Roo.dd.DragDropMgr = function() {
19167
19168     var Event = Roo.EventManager;
19169
19170     return {
19171
19172         /**
19173          * Two dimensional Array of registered DragDrop objects.  The first
19174          * dimension is the DragDrop item group, the second the DragDrop
19175          * object.
19176          * @property ids
19177          * @type {string: string}
19178          * @private
19179          * @static
19180          */
19181         ids: {},
19182
19183         /**
19184          * Array of element ids defined as drag handles.  Used to determine
19185          * if the element that generated the mousedown event is actually the
19186          * handle and not the html element itself.
19187          * @property handleIds
19188          * @type {string: string}
19189          * @private
19190          * @static
19191          */
19192         handleIds: {},
19193
19194         /**
19195          * the DragDrop object that is currently being dragged
19196          * @property dragCurrent
19197          * @type DragDrop
19198          * @private
19199          * @static
19200          **/
19201         dragCurrent: null,
19202
19203         /**
19204          * the DragDrop object(s) that are being hovered over
19205          * @property dragOvers
19206          * @type Array
19207          * @private
19208          * @static
19209          */
19210         dragOvers: {},
19211
19212         /**
19213          * the X distance between the cursor and the object being dragged
19214          * @property deltaX
19215          * @type int
19216          * @private
19217          * @static
19218          */
19219         deltaX: 0,
19220
19221         /**
19222          * the Y distance between the cursor and the object being dragged
19223          * @property deltaY
19224          * @type int
19225          * @private
19226          * @static
19227          */
19228         deltaY: 0,
19229
19230         /**
19231          * Flag to determine if we should prevent the default behavior of the
19232          * events we define. By default this is true, but this can be set to
19233          * false if you need the default behavior (not recommended)
19234          * @property preventDefault
19235          * @type boolean
19236          * @static
19237          */
19238         preventDefault: true,
19239
19240         /**
19241          * Flag to determine if we should stop the propagation of the events
19242          * we generate. This is true by default but you may want to set it to
19243          * false if the html element contains other features that require the
19244          * mouse click.
19245          * @property stopPropagation
19246          * @type boolean
19247          * @static
19248          */
19249         stopPropagation: true,
19250
19251         /**
19252          * Internal flag that is set to true when drag and drop has been
19253          * intialized
19254          * @property initialized
19255          * @private
19256          * @static
19257          */
19258         initalized: false,
19259
19260         /**
19261          * All drag and drop can be disabled.
19262          * @property locked
19263          * @private
19264          * @static
19265          */
19266         locked: false,
19267
19268         /**
19269          * Called the first time an element is registered.
19270          * @method init
19271          * @private
19272          * @static
19273          */
19274         init: function() {
19275             this.initialized = true;
19276         },
19277
19278         /**
19279          * In point mode, drag and drop interaction is defined by the
19280          * location of the cursor during the drag/drop
19281          * @property POINT
19282          * @type int
19283          * @static
19284          */
19285         POINT: 0,
19286
19287         /**
19288          * In intersect mode, drag and drop interactio nis defined by the
19289          * overlap of two or more drag and drop objects.
19290          * @property INTERSECT
19291          * @type int
19292          * @static
19293          */
19294         INTERSECT: 1,
19295
19296         /**
19297          * The current drag and drop mode.  Default: POINT
19298          * @property mode
19299          * @type int
19300          * @static
19301          */
19302         mode: 0,
19303
19304         /**
19305          * Runs method on all drag and drop objects
19306          * @method _execOnAll
19307          * @private
19308          * @static
19309          */
19310         _execOnAll: function(sMethod, args) {
19311             for (var i in this.ids) {
19312                 for (var j in this.ids[i]) {
19313                     var oDD = this.ids[i][j];
19314                     if (! this.isTypeOfDD(oDD)) {
19315                         continue;
19316                     }
19317                     oDD[sMethod].apply(oDD, args);
19318                 }
19319             }
19320         },
19321
19322         /**
19323          * Drag and drop initialization.  Sets up the global event handlers
19324          * @method _onLoad
19325          * @private
19326          * @static
19327          */
19328         _onLoad: function() {
19329
19330             this.init();
19331
19332             if (!Roo.isTouch) {
19333                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19334                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19335             }
19336             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19337             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19338             
19339             Event.on(window,   "unload",    this._onUnload, this, true);
19340             Event.on(window,   "resize",    this._onResize, this, true);
19341             // Event.on(window,   "mouseout",    this._test);
19342
19343         },
19344
19345         /**
19346          * Reset constraints on all drag and drop objs
19347          * @method _onResize
19348          * @private
19349          * @static
19350          */
19351         _onResize: function(e) {
19352             this._execOnAll("resetConstraints", []);
19353         },
19354
19355         /**
19356          * Lock all drag and drop functionality
19357          * @method lock
19358          * @static
19359          */
19360         lock: function() { this.locked = true; },
19361
19362         /**
19363          * Unlock all drag and drop functionality
19364          * @method unlock
19365          * @static
19366          */
19367         unlock: function() { this.locked = false; },
19368
19369         /**
19370          * Is drag and drop locked?
19371          * @method isLocked
19372          * @return {boolean} True if drag and drop is locked, false otherwise.
19373          * @static
19374          */
19375         isLocked: function() { return this.locked; },
19376
19377         /**
19378          * Location cache that is set for all drag drop objects when a drag is
19379          * initiated, cleared when the drag is finished.
19380          * @property locationCache
19381          * @private
19382          * @static
19383          */
19384         locationCache: {},
19385
19386         /**
19387          * Set useCache to false if you want to force object the lookup of each
19388          * drag and drop linked element constantly during a drag.
19389          * @property useCache
19390          * @type boolean
19391          * @static
19392          */
19393         useCache: true,
19394
19395         /**
19396          * The number of pixels that the mouse needs to move after the
19397          * mousedown before the drag is initiated.  Default=3;
19398          * @property clickPixelThresh
19399          * @type int
19400          * @static
19401          */
19402         clickPixelThresh: 3,
19403
19404         /**
19405          * The number of milliseconds after the mousedown event to initiate the
19406          * drag if we don't get a mouseup event. Default=1000
19407          * @property clickTimeThresh
19408          * @type int
19409          * @static
19410          */
19411         clickTimeThresh: 350,
19412
19413         /**
19414          * Flag that indicates that either the drag pixel threshold or the
19415          * mousdown time threshold has been met
19416          * @property dragThreshMet
19417          * @type boolean
19418          * @private
19419          * @static
19420          */
19421         dragThreshMet: false,
19422
19423         /**
19424          * Timeout used for the click time threshold
19425          * @property clickTimeout
19426          * @type Object
19427          * @private
19428          * @static
19429          */
19430         clickTimeout: null,
19431
19432         /**
19433          * The X position of the mousedown event stored for later use when a
19434          * drag threshold is met.
19435          * @property startX
19436          * @type int
19437          * @private
19438          * @static
19439          */
19440         startX: 0,
19441
19442         /**
19443          * The Y position of the mousedown event stored for later use when a
19444          * drag threshold is met.
19445          * @property startY
19446          * @type int
19447          * @private
19448          * @static
19449          */
19450         startY: 0,
19451
19452         /**
19453          * Each DragDrop instance must be registered with the DragDropMgr.
19454          * This is executed in DragDrop.init()
19455          * @method regDragDrop
19456          * @param {DragDrop} oDD the DragDrop object to register
19457          * @param {String} sGroup the name of the group this element belongs to
19458          * @static
19459          */
19460         regDragDrop: function(oDD, sGroup) {
19461             if (!this.initialized) { this.init(); }
19462
19463             if (!this.ids[sGroup]) {
19464                 this.ids[sGroup] = {};
19465             }
19466             this.ids[sGroup][oDD.id] = oDD;
19467         },
19468
19469         /**
19470          * Removes the supplied dd instance from the supplied group. Executed
19471          * by DragDrop.removeFromGroup, so don't call this function directly.
19472          * @method removeDDFromGroup
19473          * @private
19474          * @static
19475          */
19476         removeDDFromGroup: function(oDD, sGroup) {
19477             if (!this.ids[sGroup]) {
19478                 this.ids[sGroup] = {};
19479             }
19480
19481             var obj = this.ids[sGroup];
19482             if (obj && obj[oDD.id]) {
19483                 delete obj[oDD.id];
19484             }
19485         },
19486
19487         /**
19488          * Unregisters a drag and drop item.  This is executed in
19489          * DragDrop.unreg, use that method instead of calling this directly.
19490          * @method _remove
19491          * @private
19492          * @static
19493          */
19494         _remove: function(oDD) {
19495             for (var g in oDD.groups) {
19496                 if (g && this.ids[g][oDD.id]) {
19497                     delete this.ids[g][oDD.id];
19498                 }
19499             }
19500             delete this.handleIds[oDD.id];
19501         },
19502
19503         /**
19504          * Each DragDrop handle element must be registered.  This is done
19505          * automatically when executing DragDrop.setHandleElId()
19506          * @method regHandle
19507          * @param {String} sDDId the DragDrop id this element is a handle for
19508          * @param {String} sHandleId the id of the element that is the drag
19509          * handle
19510          * @static
19511          */
19512         regHandle: function(sDDId, sHandleId) {
19513             if (!this.handleIds[sDDId]) {
19514                 this.handleIds[sDDId] = {};
19515             }
19516             this.handleIds[sDDId][sHandleId] = sHandleId;
19517         },
19518
19519         /**
19520          * Utility function to determine if a given element has been
19521          * registered as a drag drop item.
19522          * @method isDragDrop
19523          * @param {String} id the element id to check
19524          * @return {boolean} true if this element is a DragDrop item,
19525          * false otherwise
19526          * @static
19527          */
19528         isDragDrop: function(id) {
19529             return ( this.getDDById(id) ) ? true : false;
19530         },
19531
19532         /**
19533          * Returns the drag and drop instances that are in all groups the
19534          * passed in instance belongs to.
19535          * @method getRelated
19536          * @param {DragDrop} p_oDD the obj to get related data for
19537          * @param {boolean} bTargetsOnly if true, only return targetable objs
19538          * @return {DragDrop[]} the related instances
19539          * @static
19540          */
19541         getRelated: function(p_oDD, bTargetsOnly) {
19542             var oDDs = [];
19543             for (var i in p_oDD.groups) {
19544                 for (j in this.ids[i]) {
19545                     var dd = this.ids[i][j];
19546                     if (! this.isTypeOfDD(dd)) {
19547                         continue;
19548                     }
19549                     if (!bTargetsOnly || dd.isTarget) {
19550                         oDDs[oDDs.length] = dd;
19551                     }
19552                 }
19553             }
19554
19555             return oDDs;
19556         },
19557
19558         /**
19559          * Returns true if the specified dd target is a legal target for
19560          * the specifice drag obj
19561          * @method isLegalTarget
19562          * @param {DragDrop} the drag obj
19563          * @param {DragDrop} the target
19564          * @return {boolean} true if the target is a legal target for the
19565          * dd obj
19566          * @static
19567          */
19568         isLegalTarget: function (oDD, oTargetDD) {
19569             var targets = this.getRelated(oDD, true);
19570             for (var i=0, len=targets.length;i<len;++i) {
19571                 if (targets[i].id == oTargetDD.id) {
19572                     return true;
19573                 }
19574             }
19575
19576             return false;
19577         },
19578
19579         /**
19580          * My goal is to be able to transparently determine if an object is
19581          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19582          * returns "object", oDD.constructor.toString() always returns
19583          * "DragDrop" and not the name of the subclass.  So for now it just
19584          * evaluates a well-known variable in DragDrop.
19585          * @method isTypeOfDD
19586          * @param {Object} the object to evaluate
19587          * @return {boolean} true if typeof oDD = DragDrop
19588          * @static
19589          */
19590         isTypeOfDD: function (oDD) {
19591             return (oDD && oDD.__ygDragDrop);
19592         },
19593
19594         /**
19595          * Utility function to determine if a given element has been
19596          * registered as a drag drop handle for the given Drag Drop object.
19597          * @method isHandle
19598          * @param {String} id the element id to check
19599          * @return {boolean} true if this element is a DragDrop handle, false
19600          * otherwise
19601          * @static
19602          */
19603         isHandle: function(sDDId, sHandleId) {
19604             return ( this.handleIds[sDDId] &&
19605                             this.handleIds[sDDId][sHandleId] );
19606         },
19607
19608         /**
19609          * Returns the DragDrop instance for a given id
19610          * @method getDDById
19611          * @param {String} id the id of the DragDrop object
19612          * @return {DragDrop} the drag drop object, null if it is not found
19613          * @static
19614          */
19615         getDDById: function(id) {
19616             for (var i in this.ids) {
19617                 if (this.ids[i][id]) {
19618                     return this.ids[i][id];
19619                 }
19620             }
19621             return null;
19622         },
19623
19624         /**
19625          * Fired after a registered DragDrop object gets the mousedown event.
19626          * Sets up the events required to track the object being dragged
19627          * @method handleMouseDown
19628          * @param {Event} e the event
19629          * @param oDD the DragDrop object being dragged
19630          * @private
19631          * @static
19632          */
19633         handleMouseDown: function(e, oDD) {
19634             if(Roo.QuickTips){
19635                 Roo.QuickTips.disable();
19636             }
19637             this.currentTarget = e.getTarget();
19638
19639             this.dragCurrent = oDD;
19640
19641             var el = oDD.getEl();
19642
19643             // track start position
19644             this.startX = e.getPageX();
19645             this.startY = e.getPageY();
19646
19647             this.deltaX = this.startX - el.offsetLeft;
19648             this.deltaY = this.startY - el.offsetTop;
19649
19650             this.dragThreshMet = false;
19651
19652             this.clickTimeout = setTimeout(
19653                     function() {
19654                         var DDM = Roo.dd.DDM;
19655                         DDM.startDrag(DDM.startX, DDM.startY);
19656                     },
19657                     this.clickTimeThresh );
19658         },
19659
19660         /**
19661          * Fired when either the drag pixel threshol or the mousedown hold
19662          * time threshold has been met.
19663          * @method startDrag
19664          * @param x {int} the X position of the original mousedown
19665          * @param y {int} the Y position of the original mousedown
19666          * @static
19667          */
19668         startDrag: function(x, y) {
19669             clearTimeout(this.clickTimeout);
19670             if (this.dragCurrent) {
19671                 this.dragCurrent.b4StartDrag(x, y);
19672                 this.dragCurrent.startDrag(x, y);
19673             }
19674             this.dragThreshMet = true;
19675         },
19676
19677         /**
19678          * Internal function to handle the mouseup event.  Will be invoked
19679          * from the context of the document.
19680          * @method handleMouseUp
19681          * @param {Event} e the event
19682          * @private
19683          * @static
19684          */
19685         handleMouseUp: function(e) {
19686
19687             if(Roo.QuickTips){
19688                 Roo.QuickTips.enable();
19689             }
19690             if (! this.dragCurrent) {
19691                 return;
19692             }
19693
19694             clearTimeout(this.clickTimeout);
19695
19696             if (this.dragThreshMet) {
19697                 this.fireEvents(e, true);
19698             } else {
19699             }
19700
19701             this.stopDrag(e);
19702
19703             this.stopEvent(e);
19704         },
19705
19706         /**
19707          * Utility to stop event propagation and event default, if these
19708          * features are turned on.
19709          * @method stopEvent
19710          * @param {Event} e the event as returned by this.getEvent()
19711          * @static
19712          */
19713         stopEvent: function(e){
19714             if(this.stopPropagation) {
19715                 e.stopPropagation();
19716             }
19717
19718             if (this.preventDefault) {
19719                 e.preventDefault();
19720             }
19721         },
19722
19723         /**
19724          * Internal function to clean up event handlers after the drag
19725          * operation is complete
19726          * @method stopDrag
19727          * @param {Event} e the event
19728          * @private
19729          * @static
19730          */
19731         stopDrag: function(e) {
19732             // Fire the drag end event for the item that was dragged
19733             if (this.dragCurrent) {
19734                 if (this.dragThreshMet) {
19735                     this.dragCurrent.b4EndDrag(e);
19736                     this.dragCurrent.endDrag(e);
19737                 }
19738
19739                 this.dragCurrent.onMouseUp(e);
19740             }
19741
19742             this.dragCurrent = null;
19743             this.dragOvers = {};
19744         },
19745
19746         /**
19747          * Internal function to handle the mousemove event.  Will be invoked
19748          * from the context of the html element.
19749          *
19750          * @TODO figure out what we can do about mouse events lost when the
19751          * user drags objects beyond the window boundary.  Currently we can
19752          * detect this in internet explorer by verifying that the mouse is
19753          * down during the mousemove event.  Firefox doesn't give us the
19754          * button state on the mousemove event.
19755          * @method handleMouseMove
19756          * @param {Event} e the event
19757          * @private
19758          * @static
19759          */
19760         handleMouseMove: function(e) {
19761             if (! this.dragCurrent) {
19762                 return true;
19763             }
19764
19765             // var button = e.which || e.button;
19766
19767             // check for IE mouseup outside of page boundary
19768             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19769                 this.stopEvent(e);
19770                 return this.handleMouseUp(e);
19771             }
19772
19773             if (!this.dragThreshMet) {
19774                 var diffX = Math.abs(this.startX - e.getPageX());
19775                 var diffY = Math.abs(this.startY - e.getPageY());
19776                 if (diffX > this.clickPixelThresh ||
19777                             diffY > this.clickPixelThresh) {
19778                     this.startDrag(this.startX, this.startY);
19779                 }
19780             }
19781
19782             if (this.dragThreshMet) {
19783                 this.dragCurrent.b4Drag(e);
19784                 this.dragCurrent.onDrag(e);
19785                 if(!this.dragCurrent.moveOnly){
19786                     this.fireEvents(e, false);
19787                 }
19788             }
19789
19790             this.stopEvent(e);
19791
19792             return true;
19793         },
19794
19795         /**
19796          * Iterates over all of the DragDrop elements to find ones we are
19797          * hovering over or dropping on
19798          * @method fireEvents
19799          * @param {Event} e the event
19800          * @param {boolean} isDrop is this a drop op or a mouseover op?
19801          * @private
19802          * @static
19803          */
19804         fireEvents: function(e, isDrop) {
19805             var dc = this.dragCurrent;
19806
19807             // If the user did the mouse up outside of the window, we could
19808             // get here even though we have ended the drag.
19809             if (!dc || dc.isLocked()) {
19810                 return;
19811             }
19812
19813             var pt = e.getPoint();
19814
19815             // cache the previous dragOver array
19816             var oldOvers = [];
19817
19818             var outEvts   = [];
19819             var overEvts  = [];
19820             var dropEvts  = [];
19821             var enterEvts = [];
19822
19823             // Check to see if the object(s) we were hovering over is no longer
19824             // being hovered over so we can fire the onDragOut event
19825             for (var i in this.dragOvers) {
19826
19827                 var ddo = this.dragOvers[i];
19828
19829                 if (! this.isTypeOfDD(ddo)) {
19830                     continue;
19831                 }
19832
19833                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19834                     outEvts.push( ddo );
19835                 }
19836
19837                 oldOvers[i] = true;
19838                 delete this.dragOvers[i];
19839             }
19840
19841             for (var sGroup in dc.groups) {
19842
19843                 if ("string" != typeof sGroup) {
19844                     continue;
19845                 }
19846
19847                 for (i in this.ids[sGroup]) {
19848                     var oDD = this.ids[sGroup][i];
19849                     if (! this.isTypeOfDD(oDD)) {
19850                         continue;
19851                     }
19852
19853                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19854                         if (this.isOverTarget(pt, oDD, this.mode)) {
19855                             // look for drop interactions
19856                             if (isDrop) {
19857                                 dropEvts.push( oDD );
19858                             // look for drag enter and drag over interactions
19859                             } else {
19860
19861                                 // initial drag over: dragEnter fires
19862                                 if (!oldOvers[oDD.id]) {
19863                                     enterEvts.push( oDD );
19864                                 // subsequent drag overs: dragOver fires
19865                                 } else {
19866                                     overEvts.push( oDD );
19867                                 }
19868
19869                                 this.dragOvers[oDD.id] = oDD;
19870                             }
19871                         }
19872                     }
19873                 }
19874             }
19875
19876             if (this.mode) {
19877                 if (outEvts.length) {
19878                     dc.b4DragOut(e, outEvts);
19879                     dc.onDragOut(e, outEvts);
19880                 }
19881
19882                 if (enterEvts.length) {
19883                     dc.onDragEnter(e, enterEvts);
19884                 }
19885
19886                 if (overEvts.length) {
19887                     dc.b4DragOver(e, overEvts);
19888                     dc.onDragOver(e, overEvts);
19889                 }
19890
19891                 if (dropEvts.length) {
19892                     dc.b4DragDrop(e, dropEvts);
19893                     dc.onDragDrop(e, dropEvts);
19894                 }
19895
19896             } else {
19897                 // fire dragout events
19898                 var len = 0;
19899                 for (i=0, len=outEvts.length; i<len; ++i) {
19900                     dc.b4DragOut(e, outEvts[i].id);
19901                     dc.onDragOut(e, outEvts[i].id);
19902                 }
19903
19904                 // fire enter events
19905                 for (i=0,len=enterEvts.length; i<len; ++i) {
19906                     // dc.b4DragEnter(e, oDD.id);
19907                     dc.onDragEnter(e, enterEvts[i].id);
19908                 }
19909
19910                 // fire over events
19911                 for (i=0,len=overEvts.length; i<len; ++i) {
19912                     dc.b4DragOver(e, overEvts[i].id);
19913                     dc.onDragOver(e, overEvts[i].id);
19914                 }
19915
19916                 // fire drop events
19917                 for (i=0, len=dropEvts.length; i<len; ++i) {
19918                     dc.b4DragDrop(e, dropEvts[i].id);
19919                     dc.onDragDrop(e, dropEvts[i].id);
19920                 }
19921
19922             }
19923
19924             // notify about a drop that did not find a target
19925             if (isDrop && !dropEvts.length) {
19926                 dc.onInvalidDrop(e);
19927             }
19928
19929         },
19930
19931         /**
19932          * Helper function for getting the best match from the list of drag
19933          * and drop objects returned by the drag and drop events when we are
19934          * in INTERSECT mode.  It returns either the first object that the
19935          * cursor is over, or the object that has the greatest overlap with
19936          * the dragged element.
19937          * @method getBestMatch
19938          * @param  {DragDrop[]} dds The array of drag and drop objects
19939          * targeted
19940          * @return {DragDrop}       The best single match
19941          * @static
19942          */
19943         getBestMatch: function(dds) {
19944             var winner = null;
19945             // Return null if the input is not what we expect
19946             //if (!dds || !dds.length || dds.length == 0) {
19947                // winner = null;
19948             // If there is only one item, it wins
19949             //} else if (dds.length == 1) {
19950
19951             var len = dds.length;
19952
19953             if (len == 1) {
19954                 winner = dds[0];
19955             } else {
19956                 // Loop through the targeted items
19957                 for (var i=0; i<len; ++i) {
19958                     var dd = dds[i];
19959                     // If the cursor is over the object, it wins.  If the
19960                     // cursor is over multiple matches, the first one we come
19961                     // to wins.
19962                     if (dd.cursorIsOver) {
19963                         winner = dd;
19964                         break;
19965                     // Otherwise the object with the most overlap wins
19966                     } else {
19967                         if (!winner ||
19968                             winner.overlap.getArea() < dd.overlap.getArea()) {
19969                             winner = dd;
19970                         }
19971                     }
19972                 }
19973             }
19974
19975             return winner;
19976         },
19977
19978         /**
19979          * Refreshes the cache of the top-left and bottom-right points of the
19980          * drag and drop objects in the specified group(s).  This is in the
19981          * format that is stored in the drag and drop instance, so typical
19982          * usage is:
19983          * <code>
19984          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19985          * </code>
19986          * Alternatively:
19987          * <code>
19988          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19989          * </code>
19990          * @TODO this really should be an indexed array.  Alternatively this
19991          * method could accept both.
19992          * @method refreshCache
19993          * @param {Object} groups an associative array of groups to refresh
19994          * @static
19995          */
19996         refreshCache: function(groups) {
19997             for (var sGroup in groups) {
19998                 if ("string" != typeof sGroup) {
19999                     continue;
20000                 }
20001                 for (var i in this.ids[sGroup]) {
20002                     var oDD = this.ids[sGroup][i];
20003
20004                     if (this.isTypeOfDD(oDD)) {
20005                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20006                         var loc = this.getLocation(oDD);
20007                         if (loc) {
20008                             this.locationCache[oDD.id] = loc;
20009                         } else {
20010                             delete this.locationCache[oDD.id];
20011                             // this will unregister the drag and drop object if
20012                             // the element is not in a usable state
20013                             // oDD.unreg();
20014                         }
20015                     }
20016                 }
20017             }
20018         },
20019
20020         /**
20021          * This checks to make sure an element exists and is in the DOM.  The
20022          * main purpose is to handle cases where innerHTML is used to remove
20023          * drag and drop objects from the DOM.  IE provides an 'unspecified
20024          * error' when trying to access the offsetParent of such an element
20025          * @method verifyEl
20026          * @param {HTMLElement} el the element to check
20027          * @return {boolean} true if the element looks usable
20028          * @static
20029          */
20030         verifyEl: function(el) {
20031             if (el) {
20032                 var parent;
20033                 if(Roo.isIE){
20034                     try{
20035                         parent = el.offsetParent;
20036                     }catch(e){}
20037                 }else{
20038                     parent = el.offsetParent;
20039                 }
20040                 if (parent) {
20041                     return true;
20042                 }
20043             }
20044
20045             return false;
20046         },
20047
20048         /**
20049          * Returns a Region object containing the drag and drop element's position
20050          * and size, including the padding configured for it
20051          * @method getLocation
20052          * @param {DragDrop} oDD the drag and drop object to get the
20053          *                       location for
20054          * @return {Roo.lib.Region} a Region object representing the total area
20055          *                             the element occupies, including any padding
20056          *                             the instance is configured for.
20057          * @static
20058          */
20059         getLocation: function(oDD) {
20060             if (! this.isTypeOfDD(oDD)) {
20061                 return null;
20062             }
20063
20064             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20065
20066             try {
20067                 pos= Roo.lib.Dom.getXY(el);
20068             } catch (e) { }
20069
20070             if (!pos) {
20071                 return null;
20072             }
20073
20074             x1 = pos[0];
20075             x2 = x1 + el.offsetWidth;
20076             y1 = pos[1];
20077             y2 = y1 + el.offsetHeight;
20078
20079             t = y1 - oDD.padding[0];
20080             r = x2 + oDD.padding[1];
20081             b = y2 + oDD.padding[2];
20082             l = x1 - oDD.padding[3];
20083
20084             return new Roo.lib.Region( t, r, b, l );
20085         },
20086
20087         /**
20088          * Checks the cursor location to see if it over the target
20089          * @method isOverTarget
20090          * @param {Roo.lib.Point} pt The point to evaluate
20091          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20092          * @return {boolean} true if the mouse is over the target
20093          * @private
20094          * @static
20095          */
20096         isOverTarget: function(pt, oTarget, intersect) {
20097             // use cache if available
20098             var loc = this.locationCache[oTarget.id];
20099             if (!loc || !this.useCache) {
20100                 loc = this.getLocation(oTarget);
20101                 this.locationCache[oTarget.id] = loc;
20102
20103             }
20104
20105             if (!loc) {
20106                 return false;
20107             }
20108
20109             oTarget.cursorIsOver = loc.contains( pt );
20110
20111             // DragDrop is using this as a sanity check for the initial mousedown
20112             // in this case we are done.  In POINT mode, if the drag obj has no
20113             // contraints, we are also done. Otherwise we need to evaluate the
20114             // location of the target as related to the actual location of the
20115             // dragged element.
20116             var dc = this.dragCurrent;
20117             if (!dc || !dc.getTargetCoord ||
20118                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20119                 return oTarget.cursorIsOver;
20120             }
20121
20122             oTarget.overlap = null;
20123
20124             // Get the current location of the drag element, this is the
20125             // location of the mouse event less the delta that represents
20126             // where the original mousedown happened on the element.  We
20127             // need to consider constraints and ticks as well.
20128             var pos = dc.getTargetCoord(pt.x, pt.y);
20129
20130             var el = dc.getDragEl();
20131             var curRegion = new Roo.lib.Region( pos.y,
20132                                                    pos.x + el.offsetWidth,
20133                                                    pos.y + el.offsetHeight,
20134                                                    pos.x );
20135
20136             var overlap = curRegion.intersect(loc);
20137
20138             if (overlap) {
20139                 oTarget.overlap = overlap;
20140                 return (intersect) ? true : oTarget.cursorIsOver;
20141             } else {
20142                 return false;
20143             }
20144         },
20145
20146         /**
20147          * unload event handler
20148          * @method _onUnload
20149          * @private
20150          * @static
20151          */
20152         _onUnload: function(e, me) {
20153             Roo.dd.DragDropMgr.unregAll();
20154         },
20155
20156         /**
20157          * Cleans up the drag and drop events and objects.
20158          * @method unregAll
20159          * @private
20160          * @static
20161          */
20162         unregAll: function() {
20163
20164             if (this.dragCurrent) {
20165                 this.stopDrag();
20166                 this.dragCurrent = null;
20167             }
20168
20169             this._execOnAll("unreg", []);
20170
20171             for (i in this.elementCache) {
20172                 delete this.elementCache[i];
20173             }
20174
20175             this.elementCache = {};
20176             this.ids = {};
20177         },
20178
20179         /**
20180          * A cache of DOM elements
20181          * @property elementCache
20182          * @private
20183          * @static
20184          */
20185         elementCache: {},
20186
20187         /**
20188          * Get the wrapper for the DOM element specified
20189          * @method getElWrapper
20190          * @param {String} id the id of the element to get
20191          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20192          * @private
20193          * @deprecated This wrapper isn't that useful
20194          * @static
20195          */
20196         getElWrapper: function(id) {
20197             var oWrapper = this.elementCache[id];
20198             if (!oWrapper || !oWrapper.el) {
20199                 oWrapper = this.elementCache[id] =
20200                     new this.ElementWrapper(Roo.getDom(id));
20201             }
20202             return oWrapper;
20203         },
20204
20205         /**
20206          * Returns the actual DOM element
20207          * @method getElement
20208          * @param {String} id the id of the elment to get
20209          * @return {Object} The element
20210          * @deprecated use Roo.getDom instead
20211          * @static
20212          */
20213         getElement: function(id) {
20214             return Roo.getDom(id);
20215         },
20216
20217         /**
20218          * Returns the style property for the DOM element (i.e.,
20219          * document.getElById(id).style)
20220          * @method getCss
20221          * @param {String} id the id of the elment to get
20222          * @return {Object} The style property of the element
20223          * @deprecated use Roo.getDom instead
20224          * @static
20225          */
20226         getCss: function(id) {
20227             var el = Roo.getDom(id);
20228             return (el) ? el.style : null;
20229         },
20230
20231         /**
20232          * Inner class for cached elements
20233          * @class DragDropMgr.ElementWrapper
20234          * @for DragDropMgr
20235          * @private
20236          * @deprecated
20237          */
20238         ElementWrapper: function(el) {
20239                 /**
20240                  * The element
20241                  * @property el
20242                  */
20243                 this.el = el || null;
20244                 /**
20245                  * The element id
20246                  * @property id
20247                  */
20248                 this.id = this.el && el.id;
20249                 /**
20250                  * A reference to the style property
20251                  * @property css
20252                  */
20253                 this.css = this.el && el.style;
20254             },
20255
20256         /**
20257          * Returns the X position of an html element
20258          * @method getPosX
20259          * @param el the element for which to get the position
20260          * @return {int} the X coordinate
20261          * @for DragDropMgr
20262          * @deprecated use Roo.lib.Dom.getX instead
20263          * @static
20264          */
20265         getPosX: function(el) {
20266             return Roo.lib.Dom.getX(el);
20267         },
20268
20269         /**
20270          * Returns the Y position of an html element
20271          * @method getPosY
20272          * @param el the element for which to get the position
20273          * @return {int} the Y coordinate
20274          * @deprecated use Roo.lib.Dom.getY instead
20275          * @static
20276          */
20277         getPosY: function(el) {
20278             return Roo.lib.Dom.getY(el);
20279         },
20280
20281         /**
20282          * Swap two nodes.  In IE, we use the native method, for others we
20283          * emulate the IE behavior
20284          * @method swapNode
20285          * @param n1 the first node to swap
20286          * @param n2 the other node to swap
20287          * @static
20288          */
20289         swapNode: function(n1, n2) {
20290             if (n1.swapNode) {
20291                 n1.swapNode(n2);
20292             } else {
20293                 var p = n2.parentNode;
20294                 var s = n2.nextSibling;
20295
20296                 if (s == n1) {
20297                     p.insertBefore(n1, n2);
20298                 } else if (n2 == n1.nextSibling) {
20299                     p.insertBefore(n2, n1);
20300                 } else {
20301                     n1.parentNode.replaceChild(n2, n1);
20302                     p.insertBefore(n1, s);
20303                 }
20304             }
20305         },
20306
20307         /**
20308          * Returns the current scroll position
20309          * @method getScroll
20310          * @private
20311          * @static
20312          */
20313         getScroll: function () {
20314             var t, l, dde=document.documentElement, db=document.body;
20315             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20316                 t = dde.scrollTop;
20317                 l = dde.scrollLeft;
20318             } else if (db) {
20319                 t = db.scrollTop;
20320                 l = db.scrollLeft;
20321             } else {
20322
20323             }
20324             return { top: t, left: l };
20325         },
20326
20327         /**
20328          * Returns the specified element style property
20329          * @method getStyle
20330          * @param {HTMLElement} el          the element
20331          * @param {string}      styleProp   the style property
20332          * @return {string} The value of the style property
20333          * @deprecated use Roo.lib.Dom.getStyle
20334          * @static
20335          */
20336         getStyle: function(el, styleProp) {
20337             return Roo.fly(el).getStyle(styleProp);
20338         },
20339
20340         /**
20341          * Gets the scrollTop
20342          * @method getScrollTop
20343          * @return {int} the document's scrollTop
20344          * @static
20345          */
20346         getScrollTop: function () { return this.getScroll().top; },
20347
20348         /**
20349          * Gets the scrollLeft
20350          * @method getScrollLeft
20351          * @return {int} the document's scrollTop
20352          * @static
20353          */
20354         getScrollLeft: function () { return this.getScroll().left; },
20355
20356         /**
20357          * Sets the x/y position of an element to the location of the
20358          * target element.
20359          * @method moveToEl
20360          * @param {HTMLElement} moveEl      The element to move
20361          * @param {HTMLElement} targetEl    The position reference element
20362          * @static
20363          */
20364         moveToEl: function (moveEl, targetEl) {
20365             var aCoord = Roo.lib.Dom.getXY(targetEl);
20366             Roo.lib.Dom.setXY(moveEl, aCoord);
20367         },
20368
20369         /**
20370          * Numeric array sort function
20371          * @method numericSort
20372          * @static
20373          */
20374         numericSort: function(a, b) { return (a - b); },
20375
20376         /**
20377          * Internal counter
20378          * @property _timeoutCount
20379          * @private
20380          * @static
20381          */
20382         _timeoutCount: 0,
20383
20384         /**
20385          * Trying to make the load order less important.  Without this we get
20386          * an error if this file is loaded before the Event Utility.
20387          * @method _addListeners
20388          * @private
20389          * @static
20390          */
20391         _addListeners: function() {
20392             var DDM = Roo.dd.DDM;
20393             if ( Roo.lib.Event && document ) {
20394                 DDM._onLoad();
20395             } else {
20396                 if (DDM._timeoutCount > 2000) {
20397                 } else {
20398                     setTimeout(DDM._addListeners, 10);
20399                     if (document && document.body) {
20400                         DDM._timeoutCount += 1;
20401                     }
20402                 }
20403             }
20404         },
20405
20406         /**
20407          * Recursively searches the immediate parent and all child nodes for
20408          * the handle element in order to determine wheter or not it was
20409          * clicked.
20410          * @method handleWasClicked
20411          * @param node the html element to inspect
20412          * @static
20413          */
20414         handleWasClicked: function(node, id) {
20415             if (this.isHandle(id, node.id)) {
20416                 return true;
20417             } else {
20418                 // check to see if this is a text node child of the one we want
20419                 var p = node.parentNode;
20420
20421                 while (p) {
20422                     if (this.isHandle(id, p.id)) {
20423                         return true;
20424                     } else {
20425                         p = p.parentNode;
20426                     }
20427                 }
20428             }
20429
20430             return false;
20431         }
20432
20433     };
20434
20435 }();
20436
20437 // shorter alias, save a few bytes
20438 Roo.dd.DDM = Roo.dd.DragDropMgr;
20439 Roo.dd.DDM._addListeners();
20440
20441 }/*
20442  * Based on:
20443  * Ext JS Library 1.1.1
20444  * Copyright(c) 2006-2007, Ext JS, LLC.
20445  *
20446  * Originally Released Under LGPL - original licence link has changed is not relivant.
20447  *
20448  * Fork - LGPL
20449  * <script type="text/javascript">
20450  */
20451
20452 /**
20453  * @class Roo.dd.DD
20454  * A DragDrop implementation where the linked element follows the
20455  * mouse cursor during a drag.
20456  * @extends Roo.dd.DragDrop
20457  * @constructor
20458  * @param {String} id the id of the linked element
20459  * @param {String} sGroup the group of related DragDrop items
20460  * @param {object} config an object containing configurable attributes
20461  *                Valid properties for DD:
20462  *                    scroll
20463  */
20464 Roo.dd.DD = function(id, sGroup, config) {
20465     if (id) {
20466         this.init(id, sGroup, config);
20467     }
20468 };
20469
20470 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20471
20472     /**
20473      * When set to true, the utility automatically tries to scroll the browser
20474      * window wehn a drag and drop element is dragged near the viewport boundary.
20475      * Defaults to true.
20476      * @property scroll
20477      * @type boolean
20478      */
20479     scroll: true,
20480
20481     /**
20482      * Sets the pointer offset to the distance between the linked element's top
20483      * left corner and the location the element was clicked
20484      * @method autoOffset
20485      * @param {int} iPageX the X coordinate of the click
20486      * @param {int} iPageY the Y coordinate of the click
20487      */
20488     autoOffset: function(iPageX, iPageY) {
20489         var x = iPageX - this.startPageX;
20490         var y = iPageY - this.startPageY;
20491         this.setDelta(x, y);
20492     },
20493
20494     /**
20495      * Sets the pointer offset.  You can call this directly to force the
20496      * offset to be in a particular location (e.g., pass in 0,0 to set it
20497      * to the center of the object)
20498      * @method setDelta
20499      * @param {int} iDeltaX the distance from the left
20500      * @param {int} iDeltaY the distance from the top
20501      */
20502     setDelta: function(iDeltaX, iDeltaY) {
20503         this.deltaX = iDeltaX;
20504         this.deltaY = iDeltaY;
20505     },
20506
20507     /**
20508      * Sets the drag element to the location of the mousedown or click event,
20509      * maintaining the cursor location relative to the location on the element
20510      * that was clicked.  Override this if you want to place the element in a
20511      * location other than where the cursor is.
20512      * @method setDragElPos
20513      * @param {int} iPageX the X coordinate of the mousedown or drag event
20514      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20515      */
20516     setDragElPos: function(iPageX, iPageY) {
20517         // the first time we do this, we are going to check to make sure
20518         // the element has css positioning
20519
20520         var el = this.getDragEl();
20521         this.alignElWithMouse(el, iPageX, iPageY);
20522     },
20523
20524     /**
20525      * Sets the element to the location of the mousedown or click event,
20526      * maintaining the cursor location relative to the location on the element
20527      * that was clicked.  Override this if you want to place the element in a
20528      * location other than where the cursor is.
20529      * @method alignElWithMouse
20530      * @param {HTMLElement} el the element to move
20531      * @param {int} iPageX the X coordinate of the mousedown or drag event
20532      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20533      */
20534     alignElWithMouse: function(el, iPageX, iPageY) {
20535         var oCoord = this.getTargetCoord(iPageX, iPageY);
20536         var fly = el.dom ? el : Roo.fly(el);
20537         if (!this.deltaSetXY) {
20538             var aCoord = [oCoord.x, oCoord.y];
20539             fly.setXY(aCoord);
20540             var newLeft = fly.getLeft(true);
20541             var newTop  = fly.getTop(true);
20542             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20543         } else {
20544             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20545         }
20546
20547         this.cachePosition(oCoord.x, oCoord.y);
20548         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20549         return oCoord;
20550     },
20551
20552     /**
20553      * Saves the most recent position so that we can reset the constraints and
20554      * tick marks on-demand.  We need to know this so that we can calculate the
20555      * number of pixels the element is offset from its original position.
20556      * @method cachePosition
20557      * @param iPageX the current x position (optional, this just makes it so we
20558      * don't have to look it up again)
20559      * @param iPageY the current y position (optional, this just makes it so we
20560      * don't have to look it up again)
20561      */
20562     cachePosition: function(iPageX, iPageY) {
20563         if (iPageX) {
20564             this.lastPageX = iPageX;
20565             this.lastPageY = iPageY;
20566         } else {
20567             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20568             this.lastPageX = aCoord[0];
20569             this.lastPageY = aCoord[1];
20570         }
20571     },
20572
20573     /**
20574      * Auto-scroll the window if the dragged object has been moved beyond the
20575      * visible window boundary.
20576      * @method autoScroll
20577      * @param {int} x the drag element's x position
20578      * @param {int} y the drag element's y position
20579      * @param {int} h the height of the drag element
20580      * @param {int} w the width of the drag element
20581      * @private
20582      */
20583     autoScroll: function(x, y, h, w) {
20584
20585         if (this.scroll) {
20586             // The client height
20587             var clientH = Roo.lib.Dom.getViewWidth();
20588
20589             // The client width
20590             var clientW = Roo.lib.Dom.getViewHeight();
20591
20592             // The amt scrolled down
20593             var st = this.DDM.getScrollTop();
20594
20595             // The amt scrolled right
20596             var sl = this.DDM.getScrollLeft();
20597
20598             // Location of the bottom of the element
20599             var bot = h + y;
20600
20601             // Location of the right of the element
20602             var right = w + x;
20603
20604             // The distance from the cursor to the bottom of the visible area,
20605             // adjusted so that we don't scroll if the cursor is beyond the
20606             // element drag constraints
20607             var toBot = (clientH + st - y - this.deltaY);
20608
20609             // The distance from the cursor to the right of the visible area
20610             var toRight = (clientW + sl - x - this.deltaX);
20611
20612
20613             // How close to the edge the cursor must be before we scroll
20614             // var thresh = (document.all) ? 100 : 40;
20615             var thresh = 40;
20616
20617             // How many pixels to scroll per autoscroll op.  This helps to reduce
20618             // clunky scrolling. IE is more sensitive about this ... it needs this
20619             // value to be higher.
20620             var scrAmt = (document.all) ? 80 : 30;
20621
20622             // Scroll down if we are near the bottom of the visible page and the
20623             // obj extends below the crease
20624             if ( bot > clientH && toBot < thresh ) {
20625                 window.scrollTo(sl, st + scrAmt);
20626             }
20627
20628             // Scroll up if the window is scrolled down and the top of the object
20629             // goes above the top border
20630             if ( y < st && st > 0 && y - st < thresh ) {
20631                 window.scrollTo(sl, st - scrAmt);
20632             }
20633
20634             // Scroll right if the obj is beyond the right border and the cursor is
20635             // near the border.
20636             if ( right > clientW && toRight < thresh ) {
20637                 window.scrollTo(sl + scrAmt, st);
20638             }
20639
20640             // Scroll left if the window has been scrolled to the right and the obj
20641             // extends past the left border
20642             if ( x < sl && sl > 0 && x - sl < thresh ) {
20643                 window.scrollTo(sl - scrAmt, st);
20644             }
20645         }
20646     },
20647
20648     /**
20649      * Finds the location the element should be placed if we want to move
20650      * it to where the mouse location less the click offset would place us.
20651      * @method getTargetCoord
20652      * @param {int} iPageX the X coordinate of the click
20653      * @param {int} iPageY the Y coordinate of the click
20654      * @return an object that contains the coordinates (Object.x and Object.y)
20655      * @private
20656      */
20657     getTargetCoord: function(iPageX, iPageY) {
20658
20659
20660         var x = iPageX - this.deltaX;
20661         var y = iPageY - this.deltaY;
20662
20663         if (this.constrainX) {
20664             if (x < this.minX) { x = this.minX; }
20665             if (x > this.maxX) { x = this.maxX; }
20666         }
20667
20668         if (this.constrainY) {
20669             if (y < this.minY) { y = this.minY; }
20670             if (y > this.maxY) { y = this.maxY; }
20671         }
20672
20673         x = this.getTick(x, this.xTicks);
20674         y = this.getTick(y, this.yTicks);
20675
20676
20677         return {x:x, y:y};
20678     },
20679
20680     /*
20681      * Sets up config options specific to this class. Overrides
20682      * Roo.dd.DragDrop, but all versions of this method through the
20683      * inheritance chain are called
20684      */
20685     applyConfig: function() {
20686         Roo.dd.DD.superclass.applyConfig.call(this);
20687         this.scroll = (this.config.scroll !== false);
20688     },
20689
20690     /*
20691      * Event that fires prior to the onMouseDown event.  Overrides
20692      * Roo.dd.DragDrop.
20693      */
20694     b4MouseDown: function(e) {
20695         // this.resetConstraints();
20696         this.autoOffset(e.getPageX(),
20697                             e.getPageY());
20698     },
20699
20700     /*
20701      * Event that fires prior to the onDrag event.  Overrides
20702      * Roo.dd.DragDrop.
20703      */
20704     b4Drag: function(e) {
20705         this.setDragElPos(e.getPageX(),
20706                             e.getPageY());
20707     },
20708
20709     toString: function() {
20710         return ("DD " + this.id);
20711     }
20712
20713     //////////////////////////////////////////////////////////////////////////
20714     // Debugging ygDragDrop events that can be overridden
20715     //////////////////////////////////////////////////////////////////////////
20716     /*
20717     startDrag: function(x, y) {
20718     },
20719
20720     onDrag: function(e) {
20721     },
20722
20723     onDragEnter: function(e, id) {
20724     },
20725
20726     onDragOver: function(e, id) {
20727     },
20728
20729     onDragOut: function(e, id) {
20730     },
20731
20732     onDragDrop: function(e, id) {
20733     },
20734
20735     endDrag: function(e) {
20736     }
20737
20738     */
20739
20740 });/*
20741  * Based on:
20742  * Ext JS Library 1.1.1
20743  * Copyright(c) 2006-2007, Ext JS, LLC.
20744  *
20745  * Originally Released Under LGPL - original licence link has changed is not relivant.
20746  *
20747  * Fork - LGPL
20748  * <script type="text/javascript">
20749  */
20750
20751 /**
20752  * @class Roo.dd.DDProxy
20753  * A DragDrop implementation that inserts an empty, bordered div into
20754  * the document that follows the cursor during drag operations.  At the time of
20755  * the click, the frame div is resized to the dimensions of the linked html
20756  * element, and moved to the exact location of the linked element.
20757  *
20758  * References to the "frame" element refer to the single proxy element that
20759  * was created to be dragged in place of all DDProxy elements on the
20760  * page.
20761  *
20762  * @extends Roo.dd.DD
20763  * @constructor
20764  * @param {String} id the id of the linked html element
20765  * @param {String} sGroup the group of related DragDrop objects
20766  * @param {object} config an object containing configurable attributes
20767  *                Valid properties for DDProxy in addition to those in DragDrop:
20768  *                   resizeFrame, centerFrame, dragElId
20769  */
20770 Roo.dd.DDProxy = function(id, sGroup, config) {
20771     if (id) {
20772         this.init(id, sGroup, config);
20773         this.initFrame();
20774     }
20775 };
20776
20777 /**
20778  * The default drag frame div id
20779  * @property Roo.dd.DDProxy.dragElId
20780  * @type String
20781  * @static
20782  */
20783 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20784
20785 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20786
20787     /**
20788      * By default we resize the drag frame to be the same size as the element
20789      * we want to drag (this is to get the frame effect).  We can turn it off
20790      * if we want a different behavior.
20791      * @property resizeFrame
20792      * @type boolean
20793      */
20794     resizeFrame: true,
20795
20796     /**
20797      * By default the frame is positioned exactly where the drag element is, so
20798      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20799      * you do not have constraints on the obj is to have the drag frame centered
20800      * around the cursor.  Set centerFrame to true for this effect.
20801      * @property centerFrame
20802      * @type boolean
20803      */
20804     centerFrame: false,
20805
20806     /**
20807      * Creates the proxy element if it does not yet exist
20808      * @method createFrame
20809      */
20810     createFrame: function() {
20811         var self = this;
20812         var body = document.body;
20813
20814         if (!body || !body.firstChild) {
20815             setTimeout( function() { self.createFrame(); }, 50 );
20816             return;
20817         }
20818
20819         var div = this.getDragEl();
20820
20821         if (!div) {
20822             div    = document.createElement("div");
20823             div.id = this.dragElId;
20824             var s  = div.style;
20825
20826             s.position   = "absolute";
20827             s.visibility = "hidden";
20828             s.cursor     = "move";
20829             s.border     = "2px solid #aaa";
20830             s.zIndex     = 999;
20831
20832             // appendChild can blow up IE if invoked prior to the window load event
20833             // while rendering a table.  It is possible there are other scenarios
20834             // that would cause this to happen as well.
20835             body.insertBefore(div, body.firstChild);
20836         }
20837     },
20838
20839     /**
20840      * Initialization for the drag frame element.  Must be called in the
20841      * constructor of all subclasses
20842      * @method initFrame
20843      */
20844     initFrame: function() {
20845         this.createFrame();
20846     },
20847
20848     applyConfig: function() {
20849         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20850
20851         this.resizeFrame = (this.config.resizeFrame !== false);
20852         this.centerFrame = (this.config.centerFrame);
20853         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20854     },
20855
20856     /**
20857      * Resizes the drag frame to the dimensions of the clicked object, positions
20858      * it over the object, and finally displays it
20859      * @method showFrame
20860      * @param {int} iPageX X click position
20861      * @param {int} iPageY Y click position
20862      * @private
20863      */
20864     showFrame: function(iPageX, iPageY) {
20865         var el = this.getEl();
20866         var dragEl = this.getDragEl();
20867         var s = dragEl.style;
20868
20869         this._resizeProxy();
20870
20871         if (this.centerFrame) {
20872             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20873                            Math.round(parseInt(s.height, 10)/2) );
20874         }
20875
20876         this.setDragElPos(iPageX, iPageY);
20877
20878         Roo.fly(dragEl).show();
20879     },
20880
20881     /**
20882      * The proxy is automatically resized to the dimensions of the linked
20883      * element when a drag is initiated, unless resizeFrame is set to false
20884      * @method _resizeProxy
20885      * @private
20886      */
20887     _resizeProxy: function() {
20888         if (this.resizeFrame) {
20889             var el = this.getEl();
20890             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20891         }
20892     },
20893
20894     // overrides Roo.dd.DragDrop
20895     b4MouseDown: function(e) {
20896         var x = e.getPageX();
20897         var y = e.getPageY();
20898         this.autoOffset(x, y);
20899         this.setDragElPos(x, y);
20900     },
20901
20902     // overrides Roo.dd.DragDrop
20903     b4StartDrag: function(x, y) {
20904         // show the drag frame
20905         this.showFrame(x, y);
20906     },
20907
20908     // overrides Roo.dd.DragDrop
20909     b4EndDrag: function(e) {
20910         Roo.fly(this.getDragEl()).hide();
20911     },
20912
20913     // overrides Roo.dd.DragDrop
20914     // By default we try to move the element to the last location of the frame.
20915     // This is so that the default behavior mirrors that of Roo.dd.DD.
20916     endDrag: function(e) {
20917
20918         var lel = this.getEl();
20919         var del = this.getDragEl();
20920
20921         // Show the drag frame briefly so we can get its position
20922         del.style.visibility = "";
20923
20924         this.beforeMove();
20925         // Hide the linked element before the move to get around a Safari
20926         // rendering bug.
20927         lel.style.visibility = "hidden";
20928         Roo.dd.DDM.moveToEl(lel, del);
20929         del.style.visibility = "hidden";
20930         lel.style.visibility = "";
20931
20932         this.afterDrag();
20933     },
20934
20935     beforeMove : function(){
20936
20937     },
20938
20939     afterDrag : function(){
20940
20941     },
20942
20943     toString: function() {
20944         return ("DDProxy " + this.id);
20945     }
20946
20947 });
20948 /*
20949  * Based on:
20950  * Ext JS Library 1.1.1
20951  * Copyright(c) 2006-2007, Ext JS, LLC.
20952  *
20953  * Originally Released Under LGPL - original licence link has changed is not relivant.
20954  *
20955  * Fork - LGPL
20956  * <script type="text/javascript">
20957  */
20958
20959  /**
20960  * @class Roo.dd.DDTarget
20961  * A DragDrop implementation that does not move, but can be a drop
20962  * target.  You would get the same result by simply omitting implementation
20963  * for the event callbacks, but this way we reduce the processing cost of the
20964  * event listener and the callbacks.
20965  * @extends Roo.dd.DragDrop
20966  * @constructor
20967  * @param {String} id the id of the element that is a drop target
20968  * @param {String} sGroup the group of related DragDrop objects
20969  * @param {object} config an object containing configurable attributes
20970  *                 Valid properties for DDTarget in addition to those in
20971  *                 DragDrop:
20972  *                    none
20973  */
20974 Roo.dd.DDTarget = function(id, sGroup, config) {
20975     if (id) {
20976         this.initTarget(id, sGroup, config);
20977     }
20978     if (config.listeners || config.events) { 
20979        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20980             listeners : config.listeners || {}, 
20981             events : config.events || {} 
20982         });    
20983     }
20984 };
20985
20986 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20987 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20988     toString: function() {
20989         return ("DDTarget " + this.id);
20990     }
20991 });
20992 /*
20993  * Based on:
20994  * Ext JS Library 1.1.1
20995  * Copyright(c) 2006-2007, Ext JS, LLC.
20996  *
20997  * Originally Released Under LGPL - original licence link has changed is not relivant.
20998  *
20999  * Fork - LGPL
21000  * <script type="text/javascript">
21001  */
21002  
21003
21004 /**
21005  * @class Roo.dd.ScrollManager
21006  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21007  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21008  * @singleton
21009  */
21010 Roo.dd.ScrollManager = function(){
21011     var ddm = Roo.dd.DragDropMgr;
21012     var els = {};
21013     var dragEl = null;
21014     var proc = {};
21015     
21016     
21017     
21018     var onStop = function(e){
21019         dragEl = null;
21020         clearProc();
21021     };
21022     
21023     var triggerRefresh = function(){
21024         if(ddm.dragCurrent){
21025              ddm.refreshCache(ddm.dragCurrent.groups);
21026         }
21027     };
21028     
21029     var doScroll = function(){
21030         if(ddm.dragCurrent){
21031             var dds = Roo.dd.ScrollManager;
21032             if(!dds.animate){
21033                 if(proc.el.scroll(proc.dir, dds.increment)){
21034                     triggerRefresh();
21035                 }
21036             }else{
21037                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21038             }
21039         }
21040     };
21041     
21042     var clearProc = function(){
21043         if(proc.id){
21044             clearInterval(proc.id);
21045         }
21046         proc.id = 0;
21047         proc.el = null;
21048         proc.dir = "";
21049     };
21050     
21051     var startProc = function(el, dir){
21052          Roo.log('scroll startproc');
21053         clearProc();
21054         proc.el = el;
21055         proc.dir = dir;
21056         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21057     };
21058     
21059     var onFire = function(e, isDrop){
21060        
21061         if(isDrop || !ddm.dragCurrent){ return; }
21062         var dds = Roo.dd.ScrollManager;
21063         if(!dragEl || dragEl != ddm.dragCurrent){
21064             dragEl = ddm.dragCurrent;
21065             // refresh regions on drag start
21066             dds.refreshCache();
21067         }
21068         
21069         var xy = Roo.lib.Event.getXY(e);
21070         var pt = new Roo.lib.Point(xy[0], xy[1]);
21071         for(var id in els){
21072             var el = els[id], r = el._region;
21073             if(r && r.contains(pt) && el.isScrollable()){
21074                 if(r.bottom - pt.y <= dds.thresh){
21075                     if(proc.el != el){
21076                         startProc(el, "down");
21077                     }
21078                     return;
21079                 }else if(r.right - pt.x <= dds.thresh){
21080                     if(proc.el != el){
21081                         startProc(el, "left");
21082                     }
21083                     return;
21084                 }else if(pt.y - r.top <= dds.thresh){
21085                     if(proc.el != el){
21086                         startProc(el, "up");
21087                     }
21088                     return;
21089                 }else if(pt.x - r.left <= dds.thresh){
21090                     if(proc.el != el){
21091                         startProc(el, "right");
21092                     }
21093                     return;
21094                 }
21095             }
21096         }
21097         clearProc();
21098     };
21099     
21100     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21101     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21102     
21103     return {
21104         /**
21105          * Registers new overflow element(s) to auto scroll
21106          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21107          */
21108         register : function(el){
21109             if(el instanceof Array){
21110                 for(var i = 0, len = el.length; i < len; i++) {
21111                         this.register(el[i]);
21112                 }
21113             }else{
21114                 el = Roo.get(el);
21115                 els[el.id] = el;
21116             }
21117             Roo.dd.ScrollManager.els = els;
21118         },
21119         
21120         /**
21121          * Unregisters overflow element(s) so they are no longer scrolled
21122          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21123          */
21124         unregister : function(el){
21125             if(el instanceof Array){
21126                 for(var i = 0, len = el.length; i < len; i++) {
21127                         this.unregister(el[i]);
21128                 }
21129             }else{
21130                 el = Roo.get(el);
21131                 delete els[el.id];
21132             }
21133         },
21134         
21135         /**
21136          * The number of pixels from the edge of a container the pointer needs to be to 
21137          * trigger scrolling (defaults to 25)
21138          * @type Number
21139          */
21140         thresh : 25,
21141         
21142         /**
21143          * The number of pixels to scroll in each scroll increment (defaults to 50)
21144          * @type Number
21145          */
21146         increment : 100,
21147         
21148         /**
21149          * The frequency of scrolls in milliseconds (defaults to 500)
21150          * @type Number
21151          */
21152         frequency : 500,
21153         
21154         /**
21155          * True to animate the scroll (defaults to true)
21156          * @type Boolean
21157          */
21158         animate: true,
21159         
21160         /**
21161          * The animation duration in seconds - 
21162          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21163          * @type Number
21164          */
21165         animDuration: .4,
21166         
21167         /**
21168          * Manually trigger a cache refresh.
21169          */
21170         refreshCache : function(){
21171             for(var id in els){
21172                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21173                     els[id]._region = els[id].getRegion();
21174                 }
21175             }
21176         }
21177     };
21178 }();/*
21179  * Based on:
21180  * Ext JS Library 1.1.1
21181  * Copyright(c) 2006-2007, Ext JS, LLC.
21182  *
21183  * Originally Released Under LGPL - original licence link has changed is not relivant.
21184  *
21185  * Fork - LGPL
21186  * <script type="text/javascript">
21187  */
21188  
21189
21190 /**
21191  * @class Roo.dd.Registry
21192  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21193  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21194  * @singleton
21195  */
21196 Roo.dd.Registry = function(){
21197     var elements = {}; 
21198     var handles = {}; 
21199     var autoIdSeed = 0;
21200
21201     var getId = function(el, autogen){
21202         if(typeof el == "string"){
21203             return el;
21204         }
21205         var id = el.id;
21206         if(!id && autogen !== false){
21207             id = "roodd-" + (++autoIdSeed);
21208             el.id = id;
21209         }
21210         return id;
21211     };
21212     
21213     return {
21214     /**
21215      * Register a drag drop element
21216      * @param {String|HTMLElement} element The id or DOM node to register
21217      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21218      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21219      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21220      * populated in the data object (if applicable):
21221      * <pre>
21222 Value      Description<br />
21223 ---------  ------------------------------------------<br />
21224 handles    Array of DOM nodes that trigger dragging<br />
21225            for the element being registered<br />
21226 isHandle   True if the element passed in triggers<br />
21227            dragging itself, else false
21228 </pre>
21229      */
21230         register : function(el, data){
21231             data = data || {};
21232             if(typeof el == "string"){
21233                 el = document.getElementById(el);
21234             }
21235             data.ddel = el;
21236             elements[getId(el)] = data;
21237             if(data.isHandle !== false){
21238                 handles[data.ddel.id] = data;
21239             }
21240             if(data.handles){
21241                 var hs = data.handles;
21242                 for(var i = 0, len = hs.length; i < len; i++){
21243                         handles[getId(hs[i])] = data;
21244                 }
21245             }
21246         },
21247
21248     /**
21249      * Unregister a drag drop element
21250      * @param {String|HTMLElement}  element The id or DOM node to unregister
21251      */
21252         unregister : function(el){
21253             var id = getId(el, false);
21254             var data = elements[id];
21255             if(data){
21256                 delete elements[id];
21257                 if(data.handles){
21258                     var hs = data.handles;
21259                     for(var i = 0, len = hs.length; i < len; i++){
21260                         delete handles[getId(hs[i], false)];
21261                     }
21262                 }
21263             }
21264         },
21265
21266     /**
21267      * Returns the handle registered for a DOM Node by id
21268      * @param {String|HTMLElement} id The DOM node or id to look up
21269      * @return {Object} handle The custom handle data
21270      */
21271         getHandle : function(id){
21272             if(typeof id != "string"){ // must be element?
21273                 id = id.id;
21274             }
21275             return handles[id];
21276         },
21277
21278     /**
21279      * Returns the handle that is registered for the DOM node that is the target of the event
21280      * @param {Event} e The event
21281      * @return {Object} handle The custom handle data
21282      */
21283         getHandleFromEvent : function(e){
21284             var t = Roo.lib.Event.getTarget(e);
21285             return t ? handles[t.id] : null;
21286         },
21287
21288     /**
21289      * Returns a custom data object that is registered for a DOM node by id
21290      * @param {String|HTMLElement} id The DOM node or id to look up
21291      * @return {Object} data The custom data
21292      */
21293         getTarget : function(id){
21294             if(typeof id != "string"){ // must be element?
21295                 id = id.id;
21296             }
21297             return elements[id];
21298         },
21299
21300     /**
21301      * Returns a custom data object that is registered for the DOM node that is the target of the event
21302      * @param {Event} e The event
21303      * @return {Object} data The custom data
21304      */
21305         getTargetFromEvent : function(e){
21306             var t = Roo.lib.Event.getTarget(e);
21307             return t ? elements[t.id] || handles[t.id] : null;
21308         }
21309     };
21310 }();/*
21311  * Based on:
21312  * Ext JS Library 1.1.1
21313  * Copyright(c) 2006-2007, Ext JS, LLC.
21314  *
21315  * Originally Released Under LGPL - original licence link has changed is not relivant.
21316  *
21317  * Fork - LGPL
21318  * <script type="text/javascript">
21319  */
21320  
21321
21322 /**
21323  * @class Roo.dd.StatusProxy
21324  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21325  * default drag proxy used by all Roo.dd components.
21326  * @constructor
21327  * @param {Object} config
21328  */
21329 Roo.dd.StatusProxy = function(config){
21330     Roo.apply(this, config);
21331     this.id = this.id || Roo.id();
21332     this.el = new Roo.Layer({
21333         dh: {
21334             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21335                 {tag: "div", cls: "x-dd-drop-icon"},
21336                 {tag: "div", cls: "x-dd-drag-ghost"}
21337             ]
21338         }, 
21339         shadow: !config || config.shadow !== false
21340     });
21341     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21342     this.dropStatus = this.dropNotAllowed;
21343 };
21344
21345 Roo.dd.StatusProxy.prototype = {
21346     /**
21347      * @cfg {String} dropAllowed
21348      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21349      */
21350     dropAllowed : "x-dd-drop-ok",
21351     /**
21352      * @cfg {String} dropNotAllowed
21353      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21354      */
21355     dropNotAllowed : "x-dd-drop-nodrop",
21356
21357     /**
21358      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21359      * over the current target element.
21360      * @param {String} cssClass The css class for the new drop status indicator image
21361      */
21362     setStatus : function(cssClass){
21363         cssClass = cssClass || this.dropNotAllowed;
21364         if(this.dropStatus != cssClass){
21365             this.el.replaceClass(this.dropStatus, cssClass);
21366             this.dropStatus = cssClass;
21367         }
21368     },
21369
21370     /**
21371      * Resets the status indicator to the default dropNotAllowed value
21372      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21373      */
21374     reset : function(clearGhost){
21375         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21376         this.dropStatus = this.dropNotAllowed;
21377         if(clearGhost){
21378             this.ghost.update("");
21379         }
21380     },
21381
21382     /**
21383      * Updates the contents of the ghost element
21384      * @param {String} html The html that will replace the current innerHTML of the ghost element
21385      */
21386     update : function(html){
21387         if(typeof html == "string"){
21388             this.ghost.update(html);
21389         }else{
21390             this.ghost.update("");
21391             html.style.margin = "0";
21392             this.ghost.dom.appendChild(html);
21393         }
21394         // ensure float = none set?? cant remember why though.
21395         var el = this.ghost.dom.firstChild;
21396                 if(el){
21397                         Roo.fly(el).setStyle('float', 'none');
21398                 }
21399     },
21400     
21401     /**
21402      * Returns the underlying proxy {@link Roo.Layer}
21403      * @return {Roo.Layer} el
21404     */
21405     getEl : function(){
21406         return this.el;
21407     },
21408
21409     /**
21410      * Returns the ghost element
21411      * @return {Roo.Element} el
21412      */
21413     getGhost : function(){
21414         return this.ghost;
21415     },
21416
21417     /**
21418      * Hides the proxy
21419      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21420      */
21421     hide : function(clear){
21422         this.el.hide();
21423         if(clear){
21424             this.reset(true);
21425         }
21426     },
21427
21428     /**
21429      * Stops the repair animation if it's currently running
21430      */
21431     stop : function(){
21432         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21433             this.anim.stop();
21434         }
21435     },
21436
21437     /**
21438      * Displays this proxy
21439      */
21440     show : function(){
21441         this.el.show();
21442     },
21443
21444     /**
21445      * Force the Layer to sync its shadow and shim positions to the element
21446      */
21447     sync : function(){
21448         this.el.sync();
21449     },
21450
21451     /**
21452      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21453      * invalid drop operation by the item being dragged.
21454      * @param {Array} xy The XY position of the element ([x, y])
21455      * @param {Function} callback The function to call after the repair is complete
21456      * @param {Object} scope The scope in which to execute the callback
21457      */
21458     repair : function(xy, callback, scope){
21459         this.callback = callback;
21460         this.scope = scope;
21461         if(xy && this.animRepair !== false){
21462             this.el.addClass("x-dd-drag-repair");
21463             this.el.hideUnders(true);
21464             this.anim = this.el.shift({
21465                 duration: this.repairDuration || .5,
21466                 easing: 'easeOut',
21467                 xy: xy,
21468                 stopFx: true,
21469                 callback: this.afterRepair,
21470                 scope: this
21471             });
21472         }else{
21473             this.afterRepair();
21474         }
21475     },
21476
21477     // private
21478     afterRepair : function(){
21479         this.hide(true);
21480         if(typeof this.callback == "function"){
21481             this.callback.call(this.scope || this);
21482         }
21483         this.callback = null;
21484         this.scope = null;
21485     }
21486 };/*
21487  * Based on:
21488  * Ext JS Library 1.1.1
21489  * Copyright(c) 2006-2007, Ext JS, LLC.
21490  *
21491  * Originally Released Under LGPL - original licence link has changed is not relivant.
21492  *
21493  * Fork - LGPL
21494  * <script type="text/javascript">
21495  */
21496
21497 /**
21498  * @class Roo.dd.DragSource
21499  * @extends Roo.dd.DDProxy
21500  * A simple class that provides the basic implementation needed to make any element draggable.
21501  * @constructor
21502  * @param {String/HTMLElement/Element} el The container element
21503  * @param {Object} config
21504  */
21505 Roo.dd.DragSource = function(el, config){
21506     this.el = Roo.get(el);
21507     this.dragData = {};
21508     
21509     Roo.apply(this, config);
21510     
21511     if(!this.proxy){
21512         this.proxy = new Roo.dd.StatusProxy();
21513     }
21514
21515     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21516           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21517     
21518     this.dragging = false;
21519 };
21520
21521 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21522     /**
21523      * @cfg {String} dropAllowed
21524      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21525      */
21526     dropAllowed : "x-dd-drop-ok",
21527     /**
21528      * @cfg {String} dropNotAllowed
21529      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21530      */
21531     dropNotAllowed : "x-dd-drop-nodrop",
21532
21533     /**
21534      * Returns the data object associated with this drag source
21535      * @return {Object} data An object containing arbitrary data
21536      */
21537     getDragData : function(e){
21538         return this.dragData;
21539     },
21540
21541     // private
21542     onDragEnter : function(e, id){
21543         var target = Roo.dd.DragDropMgr.getDDById(id);
21544         this.cachedTarget = target;
21545         if(this.beforeDragEnter(target, e, id) !== false){
21546             if(target.isNotifyTarget){
21547                 var status = target.notifyEnter(this, e, this.dragData);
21548                 this.proxy.setStatus(status);
21549             }else{
21550                 this.proxy.setStatus(this.dropAllowed);
21551             }
21552             
21553             if(this.afterDragEnter){
21554                 /**
21555                  * An empty function by default, but provided so that you can perform a custom action
21556                  * when the dragged item enters the drop target by providing an implementation.
21557                  * @param {Roo.dd.DragDrop} target The drop target
21558                  * @param {Event} e The event object
21559                  * @param {String} id The id of the dragged element
21560                  * @method afterDragEnter
21561                  */
21562                 this.afterDragEnter(target, e, id);
21563             }
21564         }
21565     },
21566
21567     /**
21568      * An empty function by default, but provided so that you can perform a custom action
21569      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21570      * @param {Roo.dd.DragDrop} target The drop target
21571      * @param {Event} e The event object
21572      * @param {String} id The id of the dragged element
21573      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21574      */
21575     beforeDragEnter : function(target, e, id){
21576         return true;
21577     },
21578
21579     // private
21580     alignElWithMouse: function() {
21581         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21582         this.proxy.sync();
21583     },
21584
21585     // private
21586     onDragOver : function(e, id){
21587         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21588         if(this.beforeDragOver(target, e, id) !== false){
21589             if(target.isNotifyTarget){
21590                 var status = target.notifyOver(this, e, this.dragData);
21591                 this.proxy.setStatus(status);
21592             }
21593
21594             if(this.afterDragOver){
21595                 /**
21596                  * An empty function by default, but provided so that you can perform a custom action
21597                  * while the dragged item is over the drop target by providing an implementation.
21598                  * @param {Roo.dd.DragDrop} target The drop target
21599                  * @param {Event} e The event object
21600                  * @param {String} id The id of the dragged element
21601                  * @method afterDragOver
21602                  */
21603                 this.afterDragOver(target, e, id);
21604             }
21605         }
21606     },
21607
21608     /**
21609      * An empty function by default, but provided so that you can perform a custom action
21610      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21611      * @param {Roo.dd.DragDrop} target The drop target
21612      * @param {Event} e The event object
21613      * @param {String} id The id of the dragged element
21614      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21615      */
21616     beforeDragOver : function(target, e, id){
21617         return true;
21618     },
21619
21620     // private
21621     onDragOut : function(e, id){
21622         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21623         if(this.beforeDragOut(target, e, id) !== false){
21624             if(target.isNotifyTarget){
21625                 target.notifyOut(this, e, this.dragData);
21626             }
21627             this.proxy.reset();
21628             if(this.afterDragOut){
21629                 /**
21630                  * An empty function by default, but provided so that you can perform a custom action
21631                  * after the dragged item is dragged out of the target without dropping.
21632                  * @param {Roo.dd.DragDrop} target The drop target
21633                  * @param {Event} e The event object
21634                  * @param {String} id The id of the dragged element
21635                  * @method afterDragOut
21636                  */
21637                 this.afterDragOut(target, e, id);
21638             }
21639         }
21640         this.cachedTarget = null;
21641     },
21642
21643     /**
21644      * An empty function by default, but provided so that you can perform a custom action before the dragged
21645      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21646      * @param {Roo.dd.DragDrop} target The drop target
21647      * @param {Event} e The event object
21648      * @param {String} id The id of the dragged element
21649      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21650      */
21651     beforeDragOut : function(target, e, id){
21652         return true;
21653     },
21654     
21655     // private
21656     onDragDrop : function(e, id){
21657         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21658         if(this.beforeDragDrop(target, e, id) !== false){
21659             if(target.isNotifyTarget){
21660                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21661                     this.onValidDrop(target, e, id);
21662                 }else{
21663                     this.onInvalidDrop(target, e, id);
21664                 }
21665             }else{
21666                 this.onValidDrop(target, e, id);
21667             }
21668             
21669             if(this.afterDragDrop){
21670                 /**
21671                  * An empty function by default, but provided so that you can perform a custom action
21672                  * after a valid drag drop has occurred by providing an implementation.
21673                  * @param {Roo.dd.DragDrop} target The drop target
21674                  * @param {Event} e The event object
21675                  * @param {String} id The id of the dropped element
21676                  * @method afterDragDrop
21677                  */
21678                 this.afterDragDrop(target, e, id);
21679             }
21680         }
21681         delete this.cachedTarget;
21682     },
21683
21684     /**
21685      * An empty function by default, but provided so that you can perform a custom action before the dragged
21686      * item is dropped onto the target and optionally cancel the onDragDrop.
21687      * @param {Roo.dd.DragDrop} target The drop target
21688      * @param {Event} e The event object
21689      * @param {String} id The id of the dragged element
21690      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21691      */
21692     beforeDragDrop : function(target, e, id){
21693         return true;
21694     },
21695
21696     // private
21697     onValidDrop : function(target, e, id){
21698         this.hideProxy();
21699         if(this.afterValidDrop){
21700             /**
21701              * An empty function by default, but provided so that you can perform a custom action
21702              * after a valid drop has occurred by providing an implementation.
21703              * @param {Object} target The target DD 
21704              * @param {Event} e The event object
21705              * @param {String} id The id of the dropped element
21706              * @method afterInvalidDrop
21707              */
21708             this.afterValidDrop(target, e, id);
21709         }
21710     },
21711
21712     // private
21713     getRepairXY : function(e, data){
21714         return this.el.getXY();  
21715     },
21716
21717     // private
21718     onInvalidDrop : function(target, e, id){
21719         this.beforeInvalidDrop(target, e, id);
21720         if(this.cachedTarget){
21721             if(this.cachedTarget.isNotifyTarget){
21722                 this.cachedTarget.notifyOut(this, e, this.dragData);
21723             }
21724             this.cacheTarget = null;
21725         }
21726         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21727
21728         if(this.afterInvalidDrop){
21729             /**
21730              * An empty function by default, but provided so that you can perform a custom action
21731              * after an invalid drop has occurred by providing an implementation.
21732              * @param {Event} e The event object
21733              * @param {String} id The id of the dropped element
21734              * @method afterInvalidDrop
21735              */
21736             this.afterInvalidDrop(e, id);
21737         }
21738     },
21739
21740     // private
21741     afterRepair : function(){
21742         if(Roo.enableFx){
21743             this.el.highlight(this.hlColor || "c3daf9");
21744         }
21745         this.dragging = false;
21746     },
21747
21748     /**
21749      * An empty function by default, but provided so that you can perform a custom action after an invalid
21750      * drop has occurred.
21751      * @param {Roo.dd.DragDrop} target The drop target
21752      * @param {Event} e The event object
21753      * @param {String} id The id of the dragged element
21754      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21755      */
21756     beforeInvalidDrop : function(target, e, id){
21757         return true;
21758     },
21759
21760     // private
21761     handleMouseDown : function(e){
21762         if(this.dragging) {
21763             return;
21764         }
21765         var data = this.getDragData(e);
21766         if(data && this.onBeforeDrag(data, e) !== false){
21767             this.dragData = data;
21768             this.proxy.stop();
21769             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21770         } 
21771     },
21772
21773     /**
21774      * An empty function by default, but provided so that you can perform a custom action before the initial
21775      * drag event begins and optionally cancel it.
21776      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21777      * @param {Event} e The event object
21778      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21779      */
21780     onBeforeDrag : function(data, e){
21781         return true;
21782     },
21783
21784     /**
21785      * An empty function by default, but provided so that you can perform a custom action once the initial
21786      * drag event has begun.  The drag cannot be canceled from this function.
21787      * @param {Number} x The x position of the click on the dragged object
21788      * @param {Number} y The y position of the click on the dragged object
21789      */
21790     onStartDrag : Roo.emptyFn,
21791
21792     // private - YUI override
21793     startDrag : function(x, y){
21794         this.proxy.reset();
21795         this.dragging = true;
21796         this.proxy.update("");
21797         this.onInitDrag(x, y);
21798         this.proxy.show();
21799     },
21800
21801     // private
21802     onInitDrag : function(x, y){
21803         var clone = this.el.dom.cloneNode(true);
21804         clone.id = Roo.id(); // prevent duplicate ids
21805         this.proxy.update(clone);
21806         this.onStartDrag(x, y);
21807         return true;
21808     },
21809
21810     /**
21811      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21812      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21813      */
21814     getProxy : function(){
21815         return this.proxy;  
21816     },
21817
21818     /**
21819      * Hides the drag source's {@link Roo.dd.StatusProxy}
21820      */
21821     hideProxy : function(){
21822         this.proxy.hide();  
21823         this.proxy.reset(true);
21824         this.dragging = false;
21825     },
21826
21827     // private
21828     triggerCacheRefresh : function(){
21829         Roo.dd.DDM.refreshCache(this.groups);
21830     },
21831
21832     // private - override to prevent hiding
21833     b4EndDrag: function(e) {
21834     },
21835
21836     // private - override to prevent moving
21837     endDrag : function(e){
21838         this.onEndDrag(this.dragData, e);
21839     },
21840
21841     // private
21842     onEndDrag : function(data, e){
21843     },
21844     
21845     // private - pin to cursor
21846     autoOffset : function(x, y) {
21847         this.setDelta(-12, -20);
21848     }    
21849 });/*
21850  * Based on:
21851  * Ext JS Library 1.1.1
21852  * Copyright(c) 2006-2007, Ext JS, LLC.
21853  *
21854  * Originally Released Under LGPL - original licence link has changed is not relivant.
21855  *
21856  * Fork - LGPL
21857  * <script type="text/javascript">
21858  */
21859
21860
21861 /**
21862  * @class Roo.dd.DropTarget
21863  * @extends Roo.dd.DDTarget
21864  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21865  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21866  * @constructor
21867  * @param {String/HTMLElement/Element} el The container element
21868  * @param {Object} config
21869  */
21870 Roo.dd.DropTarget = function(el, config){
21871     this.el = Roo.get(el);
21872     
21873     var listeners = false; ;
21874     if (config && config.listeners) {
21875         listeners= config.listeners;
21876         delete config.listeners;
21877     }
21878     Roo.apply(this, config);
21879     
21880     if(this.containerScroll){
21881         Roo.dd.ScrollManager.register(this.el);
21882     }
21883     this.addEvents( {
21884          /**
21885          * @scope Roo.dd.DropTarget
21886          */
21887          
21888          /**
21889          * @event enter
21890          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21891          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21892          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21893          * 
21894          * IMPORTANT : it should set this.overClass and this.dropAllowed
21895          * 
21896          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21897          * @param {Event} e The event
21898          * @param {Object} data An object containing arbitrary data supplied by the drag source
21899          */
21900         "enter" : true,
21901         
21902          /**
21903          * @event over
21904          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21905          * This method will be called on every mouse movement while the drag source is over the drop target.
21906          * This default implementation simply returns the dropAllowed config value.
21907          * 
21908          * IMPORTANT : it should set this.dropAllowed
21909          * 
21910          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21911          * @param {Event} e The event
21912          * @param {Object} data An object containing arbitrary data supplied by the drag source
21913          
21914          */
21915         "over" : true,
21916         /**
21917          * @event out
21918          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21919          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21920          * overClass (if any) from the drop element.
21921          * 
21922          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21923          * @param {Event} e The event
21924          * @param {Object} data An object containing arbitrary data supplied by the drag source
21925          */
21926          "out" : true,
21927          
21928         /**
21929          * @event drop
21930          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21931          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21932          * implementation that does something to process the drop event and returns true so that the drag source's
21933          * repair action does not run.
21934          * 
21935          * IMPORTANT : it should set this.success
21936          * 
21937          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21938          * @param {Event} e The event
21939          * @param {Object} data An object containing arbitrary data supplied by the drag source
21940         */
21941          "drop" : true
21942     });
21943             
21944      
21945     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21946         this.el.dom, 
21947         this.ddGroup || this.group,
21948         {
21949             isTarget: true,
21950             listeners : listeners || {} 
21951            
21952         
21953         }
21954     );
21955
21956 };
21957
21958 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21959     /**
21960      * @cfg {String} overClass
21961      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21962      */
21963      /**
21964      * @cfg {String} ddGroup
21965      * The drag drop group to handle drop events for
21966      */
21967      
21968     /**
21969      * @cfg {String} dropAllowed
21970      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21971      */
21972     dropAllowed : "x-dd-drop-ok",
21973     /**
21974      * @cfg {String} dropNotAllowed
21975      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21976      */
21977     dropNotAllowed : "x-dd-drop-nodrop",
21978     /**
21979      * @cfg {boolean} success
21980      * set this after drop listener.. 
21981      */
21982     success : false,
21983     /**
21984      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21985      * if the drop point is valid for over/enter..
21986      */
21987     valid : false,
21988     // private
21989     isTarget : true,
21990
21991     // private
21992     isNotifyTarget : true,
21993     
21994     /**
21995      * @hide
21996      */
21997     notifyEnter : function(dd, e, data)
21998     {
21999         this.valid = true;
22000         this.fireEvent('enter', dd, e, data);
22001         if(this.overClass){
22002             this.el.addClass(this.overClass);
22003         }
22004         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22005             this.valid ? this.dropAllowed : this.dropNotAllowed
22006         );
22007     },
22008
22009     /**
22010      * @hide
22011      */
22012     notifyOver : function(dd, e, data)
22013     {
22014         this.valid = true;
22015         this.fireEvent('over', dd, e, data);
22016         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22017             this.valid ? this.dropAllowed : this.dropNotAllowed
22018         );
22019     },
22020
22021     /**
22022      * @hide
22023      */
22024     notifyOut : function(dd, e, data)
22025     {
22026         this.fireEvent('out', dd, e, data);
22027         if(this.overClass){
22028             this.el.removeClass(this.overClass);
22029         }
22030     },
22031
22032     /**
22033      * @hide
22034      */
22035     notifyDrop : function(dd, e, data)
22036     {
22037         this.success = false;
22038         this.fireEvent('drop', dd, e, data);
22039         return this.success;
22040     }
22041 });/*
22042  * Based on:
22043  * Ext JS Library 1.1.1
22044  * Copyright(c) 2006-2007, Ext JS, LLC.
22045  *
22046  * Originally Released Under LGPL - original licence link has changed is not relivant.
22047  *
22048  * Fork - LGPL
22049  * <script type="text/javascript">
22050  */
22051
22052
22053 /**
22054  * @class Roo.dd.DragZone
22055  * @extends Roo.dd.DragSource
22056  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22057  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22058  * @constructor
22059  * @param {String/HTMLElement/Element} el The container element
22060  * @param {Object} config
22061  */
22062 Roo.dd.DragZone = function(el, config){
22063     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22064     if(this.containerScroll){
22065         Roo.dd.ScrollManager.register(this.el);
22066     }
22067 };
22068
22069 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22070     /**
22071      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22072      * for auto scrolling during drag operations.
22073      */
22074     /**
22075      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22076      * method after a failed drop (defaults to "c3daf9" - light blue)
22077      */
22078
22079     /**
22080      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22081      * for a valid target to drag based on the mouse down. Override this method
22082      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22083      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22084      * @param {EventObject} e The mouse down event
22085      * @return {Object} The dragData
22086      */
22087     getDragData : function(e){
22088         return Roo.dd.Registry.getHandleFromEvent(e);
22089     },
22090     
22091     /**
22092      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22093      * this.dragData.ddel
22094      * @param {Number} x The x position of the click on the dragged object
22095      * @param {Number} y The y position of the click on the dragged object
22096      * @return {Boolean} true to continue the drag, false to cancel
22097      */
22098     onInitDrag : function(x, y){
22099         this.proxy.update(this.dragData.ddel.cloneNode(true));
22100         this.onStartDrag(x, y);
22101         return true;
22102     },
22103     
22104     /**
22105      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22106      */
22107     afterRepair : function(){
22108         if(Roo.enableFx){
22109             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22110         }
22111         this.dragging = false;
22112     },
22113
22114     /**
22115      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22116      * the XY of this.dragData.ddel
22117      * @param {EventObject} e The mouse up event
22118      * @return {Array} The xy location (e.g. [100, 200])
22119      */
22120     getRepairXY : function(e){
22121         return Roo.Element.fly(this.dragData.ddel).getXY();  
22122     }
22123 });/*
22124  * Based on:
22125  * Ext JS Library 1.1.1
22126  * Copyright(c) 2006-2007, Ext JS, LLC.
22127  *
22128  * Originally Released Under LGPL - original licence link has changed is not relivant.
22129  *
22130  * Fork - LGPL
22131  * <script type="text/javascript">
22132  */
22133 /**
22134  * @class Roo.dd.DropZone
22135  * @extends Roo.dd.DropTarget
22136  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22137  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22138  * @constructor
22139  * @param {String/HTMLElement/Element} el The container element
22140  * @param {Object} config
22141  */
22142 Roo.dd.DropZone = function(el, config){
22143     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22144 };
22145
22146 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22147     /**
22148      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22149      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22150      * provide your own custom lookup.
22151      * @param {Event} e The event
22152      * @return {Object} data The custom data
22153      */
22154     getTargetFromEvent : function(e){
22155         return Roo.dd.Registry.getTargetFromEvent(e);
22156     },
22157
22158     /**
22159      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22160      * that it has registered.  This method has no default implementation and should be overridden to provide
22161      * node-specific processing if necessary.
22162      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22163      * {@link #getTargetFromEvent} for this node)
22164      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22165      * @param {Event} e The event
22166      * @param {Object} data An object containing arbitrary data supplied by the drag source
22167      */
22168     onNodeEnter : function(n, dd, e, data){
22169         
22170     },
22171
22172     /**
22173      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22174      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22175      * overridden to provide the proper feedback.
22176      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22177      * {@link #getTargetFromEvent} for this node)
22178      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22179      * @param {Event} e The event
22180      * @param {Object} data An object containing arbitrary data supplied by the drag source
22181      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22182      * underlying {@link Roo.dd.StatusProxy} can be updated
22183      */
22184     onNodeOver : function(n, dd, e, data){
22185         return this.dropAllowed;
22186     },
22187
22188     /**
22189      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22190      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22191      * node-specific processing if necessary.
22192      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22193      * {@link #getTargetFromEvent} for this node)
22194      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22195      * @param {Event} e The event
22196      * @param {Object} data An object containing arbitrary data supplied by the drag source
22197      */
22198     onNodeOut : function(n, dd, e, data){
22199         
22200     },
22201
22202     /**
22203      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22204      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22205      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22206      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22207      * {@link #getTargetFromEvent} for this node)
22208      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22209      * @param {Event} e The event
22210      * @param {Object} data An object containing arbitrary data supplied by the drag source
22211      * @return {Boolean} True if the drop was valid, else false
22212      */
22213     onNodeDrop : function(n, dd, e, data){
22214         return false;
22215     },
22216
22217     /**
22218      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22219      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22220      * it should be overridden to provide the proper feedback if necessary.
22221      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22222      * @param {Event} e The event
22223      * @param {Object} data An object containing arbitrary data supplied by the drag source
22224      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22225      * underlying {@link Roo.dd.StatusProxy} can be updated
22226      */
22227     onContainerOver : function(dd, e, data){
22228         return this.dropNotAllowed;
22229     },
22230
22231     /**
22232      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22233      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22234      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22235      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22236      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22237      * @param {Event} e The event
22238      * @param {Object} data An object containing arbitrary data supplied by the drag source
22239      * @return {Boolean} True if the drop was valid, else false
22240      */
22241     onContainerDrop : function(dd, e, data){
22242         return false;
22243     },
22244
22245     /**
22246      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22247      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22248      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22249      * you should override this method and provide a custom implementation.
22250      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22251      * @param {Event} e The event
22252      * @param {Object} data An object containing arbitrary data supplied by the drag source
22253      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22254      * underlying {@link Roo.dd.StatusProxy} can be updated
22255      */
22256     notifyEnter : function(dd, e, data){
22257         return this.dropNotAllowed;
22258     },
22259
22260     /**
22261      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22262      * This method will be called on every mouse movement while the drag source is over the drop zone.
22263      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22264      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22265      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22266      * registered node, it will call {@link #onContainerOver}.
22267      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22268      * @param {Event} e The event
22269      * @param {Object} data An object containing arbitrary data supplied by the drag source
22270      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22271      * underlying {@link Roo.dd.StatusProxy} can be updated
22272      */
22273     notifyOver : function(dd, e, data){
22274         var n = this.getTargetFromEvent(e);
22275         if(!n){ // not over valid drop target
22276             if(this.lastOverNode){
22277                 this.onNodeOut(this.lastOverNode, dd, e, data);
22278                 this.lastOverNode = null;
22279             }
22280             return this.onContainerOver(dd, e, data);
22281         }
22282         if(this.lastOverNode != n){
22283             if(this.lastOverNode){
22284                 this.onNodeOut(this.lastOverNode, dd, e, data);
22285             }
22286             this.onNodeEnter(n, dd, e, data);
22287             this.lastOverNode = n;
22288         }
22289         return this.onNodeOver(n, dd, e, data);
22290     },
22291
22292     /**
22293      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22294      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22295      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22296      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22297      * @param {Event} e The event
22298      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22299      */
22300     notifyOut : function(dd, e, data){
22301         if(this.lastOverNode){
22302             this.onNodeOut(this.lastOverNode, dd, e, data);
22303             this.lastOverNode = null;
22304         }
22305     },
22306
22307     /**
22308      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22309      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22310      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22311      * otherwise it will call {@link #onContainerDrop}.
22312      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22313      * @param {Event} e The event
22314      * @param {Object} data An object containing arbitrary data supplied by the drag source
22315      * @return {Boolean} True if the drop was valid, else false
22316      */
22317     notifyDrop : function(dd, e, data){
22318         if(this.lastOverNode){
22319             this.onNodeOut(this.lastOverNode, dd, e, data);
22320             this.lastOverNode = null;
22321         }
22322         var n = this.getTargetFromEvent(e);
22323         return n ?
22324             this.onNodeDrop(n, dd, e, data) :
22325             this.onContainerDrop(dd, e, data);
22326     },
22327
22328     // private
22329     triggerCacheRefresh : function(){
22330         Roo.dd.DDM.refreshCache(this.groups);
22331     }  
22332 });