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     Roo.log('-------ua---------');
54     Roo.log(ua);
55
56     var isStrict = document.compatMode == "CSS1Compat",
57         isOpera = ua.indexOf("opera") > -1,
58         isSafari = (/webkit|khtml/).test(ua),
59         isFirefox = ua.indexOf("firefox") > -1,
60         isIE = ua.indexOf("msie") > -1,
61         isIE7 = ua.indexOf("msie 7") > -1,
62         isIE11 = /trident.*rv\:11\./.test(ua),
63         isGecko = !isSafari && ua.indexOf("gecko") > -1,
64         isBorderBox = isIE && !isStrict,
65         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
66         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
67         isLinux = (ua.indexOf("linux") != -1),
68         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
69         isIOS = /iphone|ipad/.test(ua),
70         isAndroid = /android/.test(ua),
71         isTouch =  (function() {
72             try {
73                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
74                     window.addEventListener('touchstart', function __set_has_touch__ () {
75                         Roo.isTouch = true;
76                         window.removeEventListener('touchstart', __set_has_touch__);
77                     });
78                     return false; // no touch on chrome!?
79                 }
80                 document.createEvent("TouchEvent");  
81                 return true;  
82             } catch (e) {  
83                 return false;  
84             } 
85             
86         })();
87     // remove css image flicker
88         if(isIE && !isIE7){
89         try{
90             document.execCommand("BackgroundImageCache", false, true);
91         }catch(e){}
92     }
93     
94     Roo.apply(Roo, {
95         /**
96          * True if the browser is in strict mode
97          * @type Boolean
98          */
99         isStrict : isStrict,
100         /**
101          * True if the page is running over SSL
102          * @type Boolean
103          */
104         isSecure : isSecure,
105         /**
106          * True when the document is fully initialized and ready for action
107          * @type Boolean
108          */
109         isReady : false,
110         /**
111          * Turn on debugging output (currently only the factory uses this)
112          * @type Boolean
113          */
114         
115         debug: false,
116
117         /**
118          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119          * @type Boolean
120          */
121         enableGarbageCollector : true,
122
123         /**
124          * True to automatically purge event listeners after uncaching an element (defaults to false).
125          * Note: this only happens if enableGarbageCollector is true.
126          * @type Boolean
127          */
128         enableListenerCollection:false,
129
130         /**
131          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
132          * the IE insecure content warning (defaults to javascript:false).
133          * @type String
134          */
135         SSL_SECURE_URL : "javascript:false",
136
137         /**
138          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
139          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140          * @type String
141          */
142         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
143
144         emptyFn : function(){},
145         
146         /**
147          * Copies all the properties of config to obj if they don't already exist.
148          * @param {Object} obj The receiver of the properties
149          * @param {Object} config The source of the properties
150          * @return {Object} returns obj
151          */
152         applyIf : function(o, c){
153             if(o && c){
154                 for(var p in c){
155                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
156                 }
157             }
158             return o;
159         },
160
161         /**
162          * Applies event listeners to elements by selectors when the document is ready.
163          * The event name is specified with an @ suffix.
164 <pre><code>
165 Roo.addBehaviors({
166    // add a listener for click on all anchors in element with id foo
167    '#foo a@click' : function(e, t){
168        // do something
169    },
170
171    // add the same listener to multiple selectors (separated by comma BEFORE the @)
172    '#foo a, #bar span.some-class@mouseover' : function(){
173        // do something
174    }
175 });
176 </code></pre>
177          * @param {Object} obj The list of behaviors to apply
178          */
179         addBehaviors : function(o){
180             if(!Roo.isReady){
181                 Roo.onReady(function(){
182                     Roo.addBehaviors(o);
183                 });
184                 return;
185             }
186             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
187             for(var b in o){
188                 var parts = b.split('@');
189                 if(parts[1]){ // for Object prototype breakers
190                     var s = parts[0];
191                     if(!cache[s]){
192                         cache[s] = Roo.select(s);
193                     }
194                     cache[s].on(parts[1], o[b]);
195                 }
196             }
197             cache = null;
198         },
199
200         /**
201          * Generates unique ids. If the element already has an id, it is unchanged
202          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
203          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
204          * @return {String} The generated Id.
205          */
206         id : function(el, prefix){
207             prefix = prefix || "roo-gen";
208             el = Roo.getDom(el);
209             var id = prefix + (++idSeed);
210             return el ? (el.id ? el.id : (el.id = id)) : id;
211         },
212          
213        
214         /**
215          * Extends one class with another class and optionally overrides members with the passed literal. This class
216          * also adds the function "override()" to the class that can be used to override
217          * members on an instance.
218          * @param {Object} subclass The class inheriting the functionality
219          * @param {Object} superclass The class being extended
220          * @param {Object} overrides (optional) A literal with members
221          * @method extend
222          */
223         extend : function(){
224             // inline overrides
225             var io = function(o){
226                 for(var m in o){
227                     this[m] = o[m];
228                 }
229             };
230             return function(sb, sp, overrides){
231                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232                     overrides = sp;
233                     sp = sb;
234                     sb = function(){sp.apply(this, arguments);};
235                 }
236                 var F = function(){}, sbp, spp = sp.prototype;
237                 F.prototype = spp;
238                 sbp = sb.prototype = new F();
239                 sbp.constructor=sb;
240                 sb.superclass=spp;
241                 
242                 if(spp.constructor == Object.prototype.constructor){
243                     spp.constructor=sp;
244                    
245                 }
246                 
247                 sb.override = function(o){
248                     Roo.override(sb, o);
249                 };
250                 sbp.override = io;
251                 Roo.override(sb, overrides);
252                 return sb;
253             };
254         }(),
255
256         /**
257          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
258          * Usage:<pre><code>
259 Roo.override(MyClass, {
260     newMethod1: function(){
261         // etc.
262     },
263     newMethod2: function(foo){
264         // etc.
265     }
266 });
267  </code></pre>
268          * @param {Object} origclass The class to override
269          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
270          * containing one or more methods.
271          * @method override
272          */
273         override : function(origclass, overrides){
274             if(overrides){
275                 var p = origclass.prototype;
276                 for(var method in overrides){
277                     p[method] = overrides[method];
278                 }
279             }
280         },
281         /**
282          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
283          * <pre><code>
284 Roo.namespace('Company', 'Company.data');
285 Company.Widget = function() { ... }
286 Company.data.CustomStore = function(config) { ... }
287 </code></pre>
288          * @param {String} namespace1
289          * @param {String} namespace2
290          * @param {String} etc
291          * @method namespace
292          */
293         namespace : function(){
294             var a=arguments, o=null, i, j, d, rt;
295             for (i=0; i<a.length; ++i) {
296                 d=a[i].split(".");
297                 rt = d[0];
298                 /** eval:var:o */
299                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
300                 for (j=1; j<d.length; ++j) {
301                     o[d[j]]=o[d[j]] || {};
302                     o=o[d[j]];
303                 }
304             }
305         },
306         /**
307          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
308          * <pre><code>
309 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
310 Roo.factory(conf, Roo.data);
311 </code></pre>
312          * @param {String} classname
313          * @param {String} namespace (optional)
314          * @method factory
315          */
316          
317         factory : function(c, ns)
318         {
319             // no xtype, no ns or c.xns - or forced off by c.xns
320             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
321                 return c;
322             }
323             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
324             if (c.constructor == ns[c.xtype]) {// already created...
325                 return c;
326             }
327             if (ns[c.xtype]) {
328                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
329                 var ret = new ns[c.xtype](c);
330                 ret.xns = false;
331                 return ret;
332             }
333             c.xns = false; // prevent recursion..
334             return c;
335         },
336          /**
337          * Logs to console if it can.
338          *
339          * @param {String|Object} string
340          * @method log
341          */
342         log : function(s)
343         {
344             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
345                 return; // alerT?
346             }
347             console.log(s);
348             
349         },
350         /**
351          * 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.
352          * @param {Object} o
353          * @return {String}
354          */
355         urlEncode : function(o){
356             if(!o){
357                 return "";
358             }
359             var buf = [];
360             for(var key in o){
361                 var ov = o[key], k = Roo.encodeURIComponent(key);
362                 var type = typeof ov;
363                 if(type == 'undefined'){
364                     buf.push(k, "=&");
365                 }else if(type != "function" && type != "object"){
366                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
367                 }else if(ov instanceof Array){
368                     if (ov.length) {
369                             for(var i = 0, len = ov.length; i < len; i++) {
370                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
371                             }
372                         } else {
373                             buf.push(k, "=&");
374                         }
375                 }
376             }
377             buf.pop();
378             return buf.join("");
379         },
380          /**
381          * Safe version of encodeURIComponent
382          * @param {String} data 
383          * @return {String} 
384          */
385         
386         encodeURIComponent : function (data)
387         {
388             try {
389                 return encodeURIComponent(data);
390             } catch(e) {} // should be an uri encode error.
391             
392             if (data == '' || data == null){
393                return '';
394             }
395             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
396             function nibble_to_hex(nibble){
397                 var chars = '0123456789ABCDEF';
398                 return chars.charAt(nibble);
399             }
400             data = data.toString();
401             var buffer = '';
402             for(var i=0; i<data.length; i++){
403                 var c = data.charCodeAt(i);
404                 var bs = new Array();
405                 if (c > 0x10000){
406                         // 4 bytes
407                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
408                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
409                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
410                     bs[3] = 0x80 | (c & 0x3F);
411                 }else if (c > 0x800){
412                          // 3 bytes
413                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
414                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
415                     bs[2] = 0x80 | (c & 0x3F);
416                 }else if (c > 0x80){
417                        // 2 bytes
418                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
419                     bs[1] = 0x80 | (c & 0x3F);
420                 }else{
421                         // 1 byte
422                     bs[0] = c;
423                 }
424                 for(var j=0; j<bs.length; j++){
425                     var b = bs[j];
426                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
427                             + nibble_to_hex(b &0x0F);
428                     buffer += '%'+hex;
429                }
430             }
431             return buffer;    
432              
433         },
434
435         /**
436          * 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]}.
437          * @param {String} string
438          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
439          * @return {Object} A literal with members
440          */
441         urlDecode : function(string, overwrite){
442             if(!string || !string.length){
443                 return {};
444             }
445             var obj = {};
446             var pairs = string.split('&');
447             var pair, name, value;
448             for(var i = 0, len = pairs.length; i < len; i++){
449                 pair = pairs[i].split('=');
450                 name = decodeURIComponent(pair[0]);
451                 value = decodeURIComponent(pair[1]);
452                 if(overwrite !== true){
453                     if(typeof obj[name] == "undefined"){
454                         obj[name] = value;
455                     }else if(typeof obj[name] == "string"){
456                         obj[name] = [obj[name]];
457                         obj[name].push(value);
458                     }else{
459                         obj[name].push(value);
460                     }
461                 }else{
462                     obj[name] = value;
463                 }
464             }
465             return obj;
466         },
467
468         /**
469          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
470          * passed array is not really an array, your function is called once with it.
471          * The supplied function is called with (Object item, Number index, Array allItems).
472          * @param {Array/NodeList/Mixed} array
473          * @param {Function} fn
474          * @param {Object} scope
475          */
476         each : function(array, fn, scope){
477             if(typeof array.length == "undefined" || typeof array == "string"){
478                 array = [array];
479             }
480             for(var i = 0, len = array.length; i < len; i++){
481                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482             }
483         },
484
485         // deprecated
486         combine : function(){
487             var as = arguments, l = as.length, r = [];
488             for(var i = 0; i < l; i++){
489                 var a = as[i];
490                 if(a instanceof Array){
491                     r = r.concat(a);
492                 }else if(a.length !== undefined && !a.substr){
493                     r = r.concat(Array.prototype.slice.call(a, 0));
494                 }else{
495                     r.push(a);
496                 }
497             }
498             return r;
499         },
500
501         /**
502          * Escapes the passed string for use in a regular expression
503          * @param {String} str
504          * @return {String}
505          */
506         escapeRe : function(s) {
507             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
508         },
509
510         // internal
511         callback : function(cb, scope, args, delay){
512             if(typeof cb == "function"){
513                 if(delay){
514                     cb.defer(delay, scope, args || []);
515                 }else{
516                     cb.apply(scope, args || []);
517                 }
518             }
519         },
520
521         /**
522          * Return the dom node for the passed string (id), dom node, or Roo.Element
523          * @param {String/HTMLElement/Roo.Element} el
524          * @return HTMLElement
525          */
526         getDom : function(el){
527             if(!el){
528                 return null;
529             }
530             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
531         },
532
533         /**
534         * Shorthand for {@link Roo.ComponentMgr#get}
535         * @param {String} id
536         * @return Roo.Component
537         */
538         getCmp : function(id){
539             return Roo.ComponentMgr.get(id);
540         },
541          
542         num : function(v, defaultValue){
543             if(typeof v != 'number'){
544                 return defaultValue;
545             }
546             return v;
547         },
548
549         destroy : function(){
550             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
551                 var as = a[i];
552                 if(as){
553                     if(as.dom){
554                         as.removeAllListeners();
555                         as.remove();
556                         continue;
557                     }
558                     if(typeof as.purgeListeners == 'function'){
559                         as.purgeListeners();
560                     }
561                     if(typeof as.destroy == 'function'){
562                         as.destroy();
563                     }
564                 }
565             }
566         },
567
568         // inpired by a similar function in mootools library
569         /**
570          * Returns the type of object that is passed in. If the object passed in is null or undefined it
571          * return false otherwise it returns one of the following values:<ul>
572          * <li><b>string</b>: If the object passed is a string</li>
573          * <li><b>number</b>: If the object passed is a number</li>
574          * <li><b>boolean</b>: If the object passed is a boolean value</li>
575          * <li><b>function</b>: If the object passed is a function reference</li>
576          * <li><b>object</b>: If the object passed is an object</li>
577          * <li><b>array</b>: If the object passed is an array</li>
578          * <li><b>regexp</b>: If the object passed is a regular expression</li>
579          * <li><b>element</b>: If the object passed is a DOM Element</li>
580          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
581          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
582          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
583          * @param {Mixed} object
584          * @return {String}
585          */
586         type : function(o){
587             if(o === undefined || o === null){
588                 return false;
589             }
590             if(o.htmlElement){
591                 return 'element';
592             }
593             var t = typeof o;
594             if(t == 'object' && o.nodeName) {
595                 switch(o.nodeType) {
596                     case 1: return 'element';
597                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598                 }
599             }
600             if(t == 'object' || t == 'function') {
601                 switch(o.constructor) {
602                     case Array: return 'array';
603                     case RegExp: return 'regexp';
604                 }
605                 if(typeof o.length == 'number' && typeof o.item == 'function') {
606                     return 'nodelist';
607                 }
608             }
609             return t;
610         },
611
612         /**
613          * Returns true if the passed value is null, undefined or an empty string (optional).
614          * @param {Mixed} value The value to test
615          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616          * @return {Boolean}
617          */
618         isEmpty : function(v, allowBlank){
619             return v === null || v === undefined || (!allowBlank ? v === '' : false);
620         },
621         
622         /** @type Boolean */
623         isOpera : isOpera,
624         /** @type Boolean */
625         isSafari : isSafari,
626         /** @type Boolean */
627         isFirefox : isFirefox,
628         /** @type Boolean */
629         isIE : isIE,
630         /** @type Boolean */
631         isIE7 : isIE7,
632         /** @type Boolean */
633         isIE11 : isIE11,
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         fn._handlers = fn._handlers || [];
6283         
6284         
6285         fn._handlers.push([Roo.id(el), ename, h]);
6286         
6287         
6288          
6289         E.on(el, ename, h);
6290         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6291             el.addEventListener("DOMMouseScroll", h, false);
6292             E.on(window, 'unload', function(){
6293                 el.removeEventListener("DOMMouseScroll", h, false);
6294             });
6295         }
6296         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6297             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6298         }
6299         return h;
6300     };
6301
6302     var stopListening = function(el, ename, fn){
6303         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6304         if(hds){
6305             for(var i = 0, len = hds.length; i < len; i++){
6306                 var h = hds[i];
6307                 if(h[0] == id && h[1] == ename){
6308                     hd = h[2];
6309                     hds.splice(i, 1);
6310                     break;
6311                 }
6312             }
6313         }
6314         E.un(el, ename, hd);
6315         el = Roo.getDom(el);
6316         if(ename == "mousewheel" && el.addEventListener){
6317             el.removeEventListener("DOMMouseScroll", hd, false);
6318         }
6319         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6320             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6321         }
6322     };
6323
6324     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325     
6326     var pub = {
6327         
6328         
6329         /** 
6330          * Fix for doc tools
6331          * @scope Roo.EventManager
6332          */
6333         
6334         
6335         /** 
6336          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6337          * object with a Roo.EventObject
6338          * @param {Function} fn        The method the event invokes
6339          * @param {Object}   scope    An object that becomes the scope of the handler
6340          * @param {boolean}  override If true, the obj passed in becomes
6341          *                             the execution scope of the listener
6342          * @return {Function} The wrapped function
6343          * @deprecated
6344          */
6345         wrap : function(fn, scope, override){
6346             return function(e){
6347                 Roo.EventObject.setEvent(e);
6348                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6349             };
6350         },
6351         
6352         /**
6353      * Appends an event handler to an element (shorthand for addListener)
6354      * @param {String/HTMLElement}   element        The html element or id to assign the
6355      * @param {String}   eventName The type of event to listen for
6356      * @param {Function} handler The method the event invokes
6357      * @param {Object}   scope (optional) The scope in which to execute the handler
6358      * function. The handler function's "this" context.
6359      * @param {Object}   options (optional) An object containing handler configuration
6360      * properties. This may contain any of the following properties:<ul>
6361      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6362      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6363      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6364      * <li>preventDefault {Boolean} True to prevent the default action</li>
6365      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6366      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6367      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6368      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6369      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6370      * by the specified number of milliseconds. If the event fires again within that time, the original
6371      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6372      * </ul><br>
6373      * <p>
6374      * <b>Combining Options</b><br>
6375      * Using the options argument, it is possible to combine different types of listeners:<br>
6376      * <br>
6377      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6378      * Code:<pre><code>
6379 el.on('click', this.onClick, this, {
6380     single: true,
6381     delay: 100,
6382     stopEvent : true,
6383     forumId: 4
6384 });</code></pre>
6385      * <p>
6386      * <b>Attaching multiple handlers in 1 call</b><br>
6387       * The method also allows for a single argument to be passed which is a config object containing properties
6388      * which specify multiple handlers.
6389      * <p>
6390      * Code:<pre><code>
6391 el.on({
6392     'click' : {
6393         fn: this.onClick
6394         scope: this,
6395         delay: 100
6396     },
6397     'mouseover' : {
6398         fn: this.onMouseOver
6399         scope: this
6400     },
6401     'mouseout' : {
6402         fn: this.onMouseOut
6403         scope: this
6404     }
6405 });</code></pre>
6406      * <p>
6407      * Or a shorthand syntax:<br>
6408      * Code:<pre><code>
6409 el.on({
6410     'click' : this.onClick,
6411     'mouseover' : this.onMouseOver,
6412     'mouseout' : this.onMouseOut
6413     scope: this
6414 });</code></pre>
6415      */
6416         addListener : function(element, eventName, fn, scope, options){
6417             if(typeof eventName == "object"){
6418                 var o = eventName;
6419                 for(var e in o){
6420                     if(propRe.test(e)){
6421                         continue;
6422                     }
6423                     if(typeof o[e] == "function"){
6424                         // shared options
6425                         listen(element, e, o, o[e], o.scope);
6426                     }else{
6427                         // individual options
6428                         listen(element, e, o[e]);
6429                     }
6430                 }
6431                 return;
6432             }
6433             return listen(element, eventName, options, fn, scope);
6434         },
6435         
6436         /**
6437          * Removes an event handler
6438          *
6439          * @param {String/HTMLElement}   element        The id or html element to remove the 
6440          *                             event from
6441          * @param {String}   eventName     The type of event
6442          * @param {Function} fn
6443          * @return {Boolean} True if a listener was actually removed
6444          */
6445         removeListener : function(element, eventName, fn){
6446             return stopListening(element, eventName, fn);
6447         },
6448         
6449         /**
6450          * Fires when the document is ready (before onload and before images are loaded). Can be 
6451          * accessed shorthanded Roo.onReady().
6452          * @param {Function} fn        The method the event invokes
6453          * @param {Object}   scope    An  object that becomes the scope of the handler
6454          * @param {boolean}  options
6455          */
6456         onDocumentReady : function(fn, scope, options){
6457             if(docReadyState){ // if it already fired
6458                 docReadyEvent.addListener(fn, scope, options);
6459                 docReadyEvent.fire();
6460                 docReadyEvent.clearListeners();
6461                 return;
6462             }
6463             if(!docReadyEvent){
6464                 initDocReady();
6465             }
6466             docReadyEvent.addListener(fn, scope, options);
6467         },
6468         
6469         /**
6470          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6471          * @param {Function} fn        The method the event invokes
6472          * @param {Object}   scope    An object that becomes the scope of the handler
6473          * @param {boolean}  options
6474          */
6475         onWindowResize : function(fn, scope, options){
6476             if(!resizeEvent){
6477                 resizeEvent = new Roo.util.Event();
6478                 resizeTask = new Roo.util.DelayedTask(function(){
6479                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6480                 });
6481                 E.on(window, "resize", function(){
6482                     if(Roo.isIE){
6483                         resizeTask.delay(50);
6484                     }else{
6485                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6486                     }
6487                 });
6488             }
6489             resizeEvent.addListener(fn, scope, options);
6490         },
6491
6492         /**
6493          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6494          * @param {Function} fn        The method the event invokes
6495          * @param {Object}   scope    An object that becomes the scope of the handler
6496          * @param {boolean}  options
6497          */
6498         onTextResize : function(fn, scope, options){
6499             if(!textEvent){
6500                 textEvent = new Roo.util.Event();
6501                 var textEl = new Roo.Element(document.createElement('div'));
6502                 textEl.dom.className = 'x-text-resize';
6503                 textEl.dom.innerHTML = 'X';
6504                 textEl.appendTo(document.body);
6505                 textSize = textEl.dom.offsetHeight;
6506                 setInterval(function(){
6507                     if(textEl.dom.offsetHeight != textSize){
6508                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6509                     }
6510                 }, this.textResizeInterval);
6511             }
6512             textEvent.addListener(fn, scope, options);
6513         },
6514
6515         /**
6516          * Removes the passed window resize listener.
6517          * @param {Function} fn        The method the event invokes
6518          * @param {Object}   scope    The scope of handler
6519          */
6520         removeResizeListener : function(fn, scope){
6521             if(resizeEvent){
6522                 resizeEvent.removeListener(fn, scope);
6523             }
6524         },
6525
6526         // private
6527         fireResize : function(){
6528             if(resizeEvent){
6529                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6530             }   
6531         },
6532         /**
6533          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6534          */
6535         ieDeferSrc : false,
6536         /**
6537          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6538          */
6539         textResizeInterval : 50
6540     };
6541     
6542     /**
6543      * Fix for doc tools
6544      * @scopeAlias pub=Roo.EventManager
6545      */
6546     
6547      /**
6548      * Appends an event handler to an element (shorthand for addListener)
6549      * @param {String/HTMLElement}   element        The html element or id to assign the
6550      * @param {String}   eventName The type of event to listen for
6551      * @param {Function} handler The method the event invokes
6552      * @param {Object}   scope (optional) The scope in which to execute the handler
6553      * function. The handler function's "this" context.
6554      * @param {Object}   options (optional) An object containing handler configuration
6555      * properties. This may contain any of the following properties:<ul>
6556      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6557      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6558      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6559      * <li>preventDefault {Boolean} True to prevent the default action</li>
6560      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6561      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6562      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6563      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6564      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6565      * by the specified number of milliseconds. If the event fires again within that time, the original
6566      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6567      * </ul><br>
6568      * <p>
6569      * <b>Combining Options</b><br>
6570      * Using the options argument, it is possible to combine different types of listeners:<br>
6571      * <br>
6572      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6573      * Code:<pre><code>
6574 el.on('click', this.onClick, this, {
6575     single: true,
6576     delay: 100,
6577     stopEvent : true,
6578     forumId: 4
6579 });</code></pre>
6580      * <p>
6581      * <b>Attaching multiple handlers in 1 call</b><br>
6582       * The method also allows for a single argument to be passed which is a config object containing properties
6583      * which specify multiple handlers.
6584      * <p>
6585      * Code:<pre><code>
6586 el.on({
6587     'click' : {
6588         fn: this.onClick
6589         scope: this,
6590         delay: 100
6591     },
6592     'mouseover' : {
6593         fn: this.onMouseOver
6594         scope: this
6595     },
6596     'mouseout' : {
6597         fn: this.onMouseOut
6598         scope: this
6599     }
6600 });</code></pre>
6601      * <p>
6602      * Or a shorthand syntax:<br>
6603      * Code:<pre><code>
6604 el.on({
6605     'click' : this.onClick,
6606     'mouseover' : this.onMouseOver,
6607     'mouseout' : this.onMouseOut
6608     scope: this
6609 });</code></pre>
6610      */
6611     pub.on = pub.addListener;
6612     pub.un = pub.removeListener;
6613
6614     pub.stoppedMouseDownEvent = new Roo.util.Event();
6615     return pub;
6616 }();
6617 /**
6618   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6619   * @param {Function} fn        The method the event invokes
6620   * @param {Object}   scope    An  object that becomes the scope of the handler
6621   * @param {boolean}  override If true, the obj passed in becomes
6622   *                             the execution scope of the listener
6623   * @member Roo
6624   * @method onReady
6625  */
6626 Roo.onReady = Roo.EventManager.onDocumentReady;
6627
6628 Roo.onReady(function(){
6629     var bd = Roo.get(document.body);
6630     if(!bd){ return; }
6631
6632     var cls = [
6633             Roo.isIE ? "roo-ie"
6634             : Roo.isIE11 ? "roo-ie11"
6635             : Roo.isGecko ? "roo-gecko"
6636             : Roo.isOpera ? "roo-opera"
6637             : Roo.isSafari ? "roo-safari" : ""];
6638
6639     if(Roo.isMac){
6640         cls.push("roo-mac");
6641     }
6642     if(Roo.isLinux){
6643         cls.push("roo-linux");
6644     }
6645     if(Roo.isIOS){
6646         cls.push("roo-ios");
6647     }
6648     if(Roo.isTouch){
6649         cls.push("roo-touch");
6650     }
6651     if(Roo.isBorderBox){
6652         cls.push('roo-border-box');
6653     }
6654     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6655         var p = bd.dom.parentNode;
6656         if(p){
6657             p.className += ' roo-strict';
6658         }
6659     }
6660     bd.addClass(cls.join(' '));
6661 });
6662
6663 /**
6664  * @class Roo.EventObject
6665  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6666  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6667  * Example:
6668  * <pre><code>
6669  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6670     e.preventDefault();
6671     var target = e.getTarget();
6672     ...
6673  }
6674  var myDiv = Roo.get("myDiv");
6675  myDiv.on("click", handleClick);
6676  //or
6677  Roo.EventManager.on("myDiv", 'click', handleClick);
6678  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6679  </code></pre>
6680  * @singleton
6681  */
6682 Roo.EventObject = function(){
6683     
6684     var E = Roo.lib.Event;
6685     
6686     // safari keypress events for special keys return bad keycodes
6687     var safariKeys = {
6688         63234 : 37, // left
6689         63235 : 39, // right
6690         63232 : 38, // up
6691         63233 : 40, // down
6692         63276 : 33, // page up
6693         63277 : 34, // page down
6694         63272 : 46, // delete
6695         63273 : 36, // home
6696         63275 : 35  // end
6697     };
6698
6699     // normalize button clicks
6700     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6701                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6702
6703     Roo.EventObjectImpl = function(e){
6704         if(e){
6705             this.setEvent(e.browserEvent || e);
6706         }
6707     };
6708     Roo.EventObjectImpl.prototype = {
6709         /**
6710          * Used to fix doc tools.
6711          * @scope Roo.EventObject.prototype
6712          */
6713             
6714
6715         
6716         
6717         /** The normal browser event */
6718         browserEvent : null,
6719         /** The button pressed in a mouse event */
6720         button : -1,
6721         /** True if the shift key was down during the event */
6722         shiftKey : false,
6723         /** True if the control key was down during the event */
6724         ctrlKey : false,
6725         /** True if the alt key was down during the event */
6726         altKey : false,
6727
6728         /** Key constant 
6729         * @type Number */
6730         BACKSPACE : 8,
6731         /** Key constant 
6732         * @type Number */
6733         TAB : 9,
6734         /** Key constant 
6735         * @type Number */
6736         RETURN : 13,
6737         /** Key constant 
6738         * @type Number */
6739         ENTER : 13,
6740         /** Key constant 
6741         * @type Number */
6742         SHIFT : 16,
6743         /** Key constant 
6744         * @type Number */
6745         CONTROL : 17,
6746         /** Key constant 
6747         * @type Number */
6748         ESC : 27,
6749         /** Key constant 
6750         * @type Number */
6751         SPACE : 32,
6752         /** Key constant 
6753         * @type Number */
6754         PAGEUP : 33,
6755         /** Key constant 
6756         * @type Number */
6757         PAGEDOWN : 34,
6758         /** Key constant 
6759         * @type Number */
6760         END : 35,
6761         /** Key constant 
6762         * @type Number */
6763         HOME : 36,
6764         /** Key constant 
6765         * @type Number */
6766         LEFT : 37,
6767         /** Key constant 
6768         * @type Number */
6769         UP : 38,
6770         /** Key constant 
6771         * @type Number */
6772         RIGHT : 39,
6773         /** Key constant 
6774         * @type Number */
6775         DOWN : 40,
6776         /** Key constant 
6777         * @type Number */
6778         DELETE : 46,
6779         /** Key constant 
6780         * @type Number */
6781         F5 : 116,
6782
6783            /** @private */
6784         setEvent : function(e){
6785             if(e == this || (e && e.browserEvent)){ // already wrapped
6786                 return e;
6787             }
6788             this.browserEvent = e;
6789             if(e){
6790                 // normalize buttons
6791                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6792                 if(e.type == 'click' && this.button == -1){
6793                     this.button = 0;
6794                 }
6795                 this.type = e.type;
6796                 this.shiftKey = e.shiftKey;
6797                 // mac metaKey behaves like ctrlKey
6798                 this.ctrlKey = e.ctrlKey || e.metaKey;
6799                 this.altKey = e.altKey;
6800                 // in getKey these will be normalized for the mac
6801                 this.keyCode = e.keyCode;
6802                 // keyup warnings on firefox.
6803                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6804                 // cache the target for the delayed and or buffered events
6805                 this.target = E.getTarget(e);
6806                 // same for XY
6807                 this.xy = E.getXY(e);
6808             }else{
6809                 this.button = -1;
6810                 this.shiftKey = false;
6811                 this.ctrlKey = false;
6812                 this.altKey = false;
6813                 this.keyCode = 0;
6814                 this.charCode =0;
6815                 this.target = null;
6816                 this.xy = [0, 0];
6817             }
6818             return this;
6819         },
6820
6821         /**
6822          * Stop the event (preventDefault and stopPropagation)
6823          */
6824         stopEvent : function(){
6825             if(this.browserEvent){
6826                 if(this.browserEvent.type == 'mousedown'){
6827                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6828                 }
6829                 E.stopEvent(this.browserEvent);
6830             }
6831         },
6832
6833         /**
6834          * Prevents the browsers default handling of the event.
6835          */
6836         preventDefault : function(){
6837             if(this.browserEvent){
6838                 E.preventDefault(this.browserEvent);
6839             }
6840         },
6841
6842         /** @private */
6843         isNavKeyPress : function(){
6844             var k = this.keyCode;
6845             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6846             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6847         },
6848
6849         isSpecialKey : function(){
6850             var k = this.keyCode;
6851             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6852             (k == 16) || (k == 17) ||
6853             (k >= 18 && k <= 20) ||
6854             (k >= 33 && k <= 35) ||
6855             (k >= 36 && k <= 39) ||
6856             (k >= 44 && k <= 45);
6857         },
6858         /**
6859          * Cancels bubbling of the event.
6860          */
6861         stopPropagation : function(){
6862             if(this.browserEvent){
6863                 if(this.type == 'mousedown'){
6864                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6865                 }
6866                 E.stopPropagation(this.browserEvent);
6867             }
6868         },
6869
6870         /**
6871          * Gets the key code for the event.
6872          * @return {Number}
6873          */
6874         getCharCode : function(){
6875             return this.charCode || this.keyCode;
6876         },
6877
6878         /**
6879          * Returns a normalized keyCode for the event.
6880          * @return {Number} The key code
6881          */
6882         getKey : function(){
6883             var k = this.keyCode || this.charCode;
6884             return Roo.isSafari ? (safariKeys[k] || k) : k;
6885         },
6886
6887         /**
6888          * Gets the x coordinate of the event.
6889          * @return {Number}
6890          */
6891         getPageX : function(){
6892             return this.xy[0];
6893         },
6894
6895         /**
6896          * Gets the y coordinate of the event.
6897          * @return {Number}
6898          */
6899         getPageY : function(){
6900             return this.xy[1];
6901         },
6902
6903         /**
6904          * Gets the time of the event.
6905          * @return {Number}
6906          */
6907         getTime : function(){
6908             if(this.browserEvent){
6909                 return E.getTime(this.browserEvent);
6910             }
6911             return null;
6912         },
6913
6914         /**
6915          * Gets the page coordinates of the event.
6916          * @return {Array} The xy values like [x, y]
6917          */
6918         getXY : function(){
6919             return this.xy;
6920         },
6921
6922         /**
6923          * Gets the target for the event.
6924          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6925          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6926                 search as a number or element (defaults to 10 || document.body)
6927          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6928          * @return {HTMLelement}
6929          */
6930         getTarget : function(selector, maxDepth, returnEl){
6931             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6932         },
6933         /**
6934          * Gets the related target.
6935          * @return {HTMLElement}
6936          */
6937         getRelatedTarget : function(){
6938             if(this.browserEvent){
6939                 return E.getRelatedTarget(this.browserEvent);
6940             }
6941             return null;
6942         },
6943
6944         /**
6945          * Normalizes mouse wheel delta across browsers
6946          * @return {Number} The delta
6947          */
6948         getWheelDelta : function(){
6949             var e = this.browserEvent;
6950             var delta = 0;
6951             if(e.wheelDelta){ /* IE/Opera. */
6952                 delta = e.wheelDelta/120;
6953             }else if(e.detail){ /* Mozilla case. */
6954                 delta = -e.detail/3;
6955             }
6956             return delta;
6957         },
6958
6959         /**
6960          * Returns true if the control, meta, shift or alt key was pressed during this event.
6961          * @return {Boolean}
6962          */
6963         hasModifier : function(){
6964             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6965         },
6966
6967         /**
6968          * Returns true if the target of this event equals el or is a child of el
6969          * @param {String/HTMLElement/Element} el
6970          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6971          * @return {Boolean}
6972          */
6973         within : function(el, related){
6974             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6975             return t && Roo.fly(el).contains(t);
6976         },
6977
6978         getPoint : function(){
6979             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6980         }
6981     };
6982
6983     return new Roo.EventObjectImpl();
6984 }();
6985             
6986     /*
6987  * Based on:
6988  * Ext JS Library 1.1.1
6989  * Copyright(c) 2006-2007, Ext JS, LLC.
6990  *
6991  * Originally Released Under LGPL - original licence link has changed is not relivant.
6992  *
6993  * Fork - LGPL
6994  * <script type="text/javascript">
6995  */
6996
6997  
6998 // was in Composite Element!??!?!
6999  
7000 (function(){
7001     var D = Roo.lib.Dom;
7002     var E = Roo.lib.Event;
7003     var A = Roo.lib.Anim;
7004
7005     // local style camelizing for speed
7006     var propCache = {};
7007     var camelRe = /(-[a-z])/gi;
7008     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7009     var view = document.defaultView;
7010
7011 /**
7012  * @class Roo.Element
7013  * Represents an Element in the DOM.<br><br>
7014  * Usage:<br>
7015 <pre><code>
7016 var el = Roo.get("my-div");
7017
7018 // or with getEl
7019 var el = getEl("my-div");
7020
7021 // or with a DOM element
7022 var el = Roo.get(myDivElement);
7023 </code></pre>
7024  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7025  * each call instead of constructing a new one.<br><br>
7026  * <b>Animations</b><br />
7027  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7028  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7029 <pre>
7030 Option    Default   Description
7031 --------- --------  ---------------------------------------------
7032 duration  .35       The duration of the animation in seconds
7033 easing    easeOut   The YUI easing method
7034 callback  none      A function to execute when the anim completes
7035 scope     this      The scope (this) of the callback function
7036 </pre>
7037 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7038 * manipulate the animation. Here's an example:
7039 <pre><code>
7040 var el = Roo.get("my-div");
7041
7042 // no animation
7043 el.setWidth(100);
7044
7045 // default animation
7046 el.setWidth(100, true);
7047
7048 // animation with some options set
7049 el.setWidth(100, {
7050     duration: 1,
7051     callback: this.foo,
7052     scope: this
7053 });
7054
7055 // using the "anim" property to get the Anim object
7056 var opt = {
7057     duration: 1,
7058     callback: this.foo,
7059     scope: this
7060 };
7061 el.setWidth(100, opt);
7062 ...
7063 if(opt.anim.isAnimated()){
7064     opt.anim.stop();
7065 }
7066 </code></pre>
7067 * <b> Composite (Collections of) Elements</b><br />
7068  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7069  * @constructor Create a new Element directly.
7070  * @param {String/HTMLElement} element
7071  * @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).
7072  */
7073     Roo.Element = function(element, forceNew){
7074         var dom = typeof element == "string" ?
7075                 document.getElementById(element) : element;
7076         if(!dom){ // invalid id/element
7077             return null;
7078         }
7079         var id = dom.id;
7080         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7081             return Roo.Element.cache[id];
7082         }
7083
7084         /**
7085          * The DOM element
7086          * @type HTMLElement
7087          */
7088         this.dom = dom;
7089
7090         /**
7091          * The DOM element ID
7092          * @type String
7093          */
7094         this.id = id || Roo.id(dom);
7095     };
7096
7097     var El = Roo.Element;
7098
7099     El.prototype = {
7100         /**
7101          * The element's default display mode  (defaults to "")
7102          * @type String
7103          */
7104         originalDisplay : "",
7105
7106         visibilityMode : 1,
7107         /**
7108          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7109          * @type String
7110          */
7111         defaultUnit : "px",
7112         
7113         /**
7114          * Sets the element's visibility mode. When setVisible() is called it
7115          * will use this to determine whether to set the visibility or the display property.
7116          * @param visMode Element.VISIBILITY or Element.DISPLAY
7117          * @return {Roo.Element} this
7118          */
7119         setVisibilityMode : function(visMode){
7120             this.visibilityMode = visMode;
7121             return this;
7122         },
7123         /**
7124          * Convenience method for setVisibilityMode(Element.DISPLAY)
7125          * @param {String} display (optional) What to set display to when visible
7126          * @return {Roo.Element} this
7127          */
7128         enableDisplayMode : function(display){
7129             this.setVisibilityMode(El.DISPLAY);
7130             if(typeof display != "undefined") { this.originalDisplay = display; }
7131             return this;
7132         },
7133
7134         /**
7135          * 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)
7136          * @param {String} selector The simple selector to test
7137          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7138                 search as a number or element (defaults to 10 || document.body)
7139          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7140          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7141          */
7142         findParent : function(simpleSelector, maxDepth, returnEl){
7143             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7144             maxDepth = maxDepth || 50;
7145             if(typeof maxDepth != "number"){
7146                 stopEl = Roo.getDom(maxDepth);
7147                 maxDepth = 10;
7148             }
7149             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7150                 if(dq.is(p, simpleSelector)){
7151                     return returnEl ? Roo.get(p) : p;
7152                 }
7153                 depth++;
7154                 p = p.parentNode;
7155             }
7156             return null;
7157         },
7158
7159
7160         /**
7161          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7162          * @param {String} selector The simple selector to test
7163          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7164                 search as a number or element (defaults to 10 || document.body)
7165          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7166          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7167          */
7168         findParentNode : function(simpleSelector, maxDepth, returnEl){
7169             var p = Roo.fly(this.dom.parentNode, '_internal');
7170             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7171         },
7172         
7173         /**
7174          * Looks at  the scrollable parent element
7175          */
7176         findScrollableParent : function()
7177         {
7178             var overflowRegex = /(auto|scroll)/;
7179             
7180             if(this.getStyle('position') === 'fixed'){
7181                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7182             }
7183             
7184             var excludeStaticParent = this.getStyle('position') === "absolute";
7185             
7186             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7187                 
7188                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7189                     continue;
7190                 }
7191                 
7192                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7193                     return parent;
7194                 }
7195                 
7196                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7197                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7198                 }
7199             }
7200             
7201             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7202         },
7203
7204         /**
7205          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7206          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7207          * @param {String} selector The simple selector to test
7208          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7209                 search as a number or element (defaults to 10 || document.body)
7210          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7211          */
7212         up : function(simpleSelector, maxDepth){
7213             return this.findParentNode(simpleSelector, maxDepth, true);
7214         },
7215
7216
7217
7218         /**
7219          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7220          * @param {String} selector The simple selector to test
7221          * @return {Boolean} True if this element matches the selector, else false
7222          */
7223         is : function(simpleSelector){
7224             return Roo.DomQuery.is(this.dom, simpleSelector);
7225         },
7226
7227         /**
7228          * Perform animation on this element.
7229          * @param {Object} args The YUI animation control args
7230          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7231          * @param {Function} onComplete (optional) Function to call when animation completes
7232          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7233          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7234          * @return {Roo.Element} this
7235          */
7236         animate : function(args, duration, onComplete, easing, animType){
7237             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7238             return this;
7239         },
7240
7241         /*
7242          * @private Internal animation call
7243          */
7244         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7245             animType = animType || 'run';
7246             opt = opt || {};
7247             var anim = Roo.lib.Anim[animType](
7248                 this.dom, args,
7249                 (opt.duration || defaultDur) || .35,
7250                 (opt.easing || defaultEase) || 'easeOut',
7251                 function(){
7252                     Roo.callback(cb, this);
7253                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7254                 },
7255                 this
7256             );
7257             opt.anim = anim;
7258             return anim;
7259         },
7260
7261         // private legacy anim prep
7262         preanim : function(a, i){
7263             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7264         },
7265
7266         /**
7267          * Removes worthless text nodes
7268          * @param {Boolean} forceReclean (optional) By default the element
7269          * keeps track if it has been cleaned already so
7270          * you can call this over and over. However, if you update the element and
7271          * need to force a reclean, you can pass true.
7272          */
7273         clean : function(forceReclean){
7274             if(this.isCleaned && forceReclean !== true){
7275                 return this;
7276             }
7277             var ns = /\S/;
7278             var d = this.dom, n = d.firstChild, ni = -1;
7279             while(n){
7280                 var nx = n.nextSibling;
7281                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7282                     d.removeChild(n);
7283                 }else{
7284                     n.nodeIndex = ++ni;
7285                 }
7286                 n = nx;
7287             }
7288             this.isCleaned = true;
7289             return this;
7290         },
7291
7292         // private
7293         calcOffsetsTo : function(el){
7294             el = Roo.get(el);
7295             var d = el.dom;
7296             var restorePos = false;
7297             if(el.getStyle('position') == 'static'){
7298                 el.position('relative');
7299                 restorePos = true;
7300             }
7301             var x = 0, y =0;
7302             var op = this.dom;
7303             while(op && op != d && op.tagName != 'HTML'){
7304                 x+= op.offsetLeft;
7305                 y+= op.offsetTop;
7306                 op = op.offsetParent;
7307             }
7308             if(restorePos){
7309                 el.position('static');
7310             }
7311             return [x, y];
7312         },
7313
7314         /**
7315          * Scrolls this element into view within the passed container.
7316          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7317          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7318          * @return {Roo.Element} this
7319          */
7320         scrollIntoView : function(container, hscroll){
7321             var c = Roo.getDom(container) || document.body;
7322             var el = this.dom;
7323
7324             var o = this.calcOffsetsTo(c),
7325                 l = o[0],
7326                 t = o[1],
7327                 b = t+el.offsetHeight,
7328                 r = l+el.offsetWidth;
7329
7330             var ch = c.clientHeight;
7331             var ct = parseInt(c.scrollTop, 10);
7332             var cl = parseInt(c.scrollLeft, 10);
7333             var cb = ct + ch;
7334             var cr = cl + c.clientWidth;
7335
7336             if(t < ct){
7337                 c.scrollTop = t;
7338             }else if(b > cb){
7339                 c.scrollTop = b-ch;
7340             }
7341
7342             if(hscroll !== false){
7343                 if(l < cl){
7344                     c.scrollLeft = l;
7345                 }else if(r > cr){
7346                     c.scrollLeft = r-c.clientWidth;
7347                 }
7348             }
7349             return this;
7350         },
7351
7352         // private
7353         scrollChildIntoView : function(child, hscroll){
7354             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7355         },
7356
7357         /**
7358          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7359          * the new height may not be available immediately.
7360          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7361          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7362          * @param {Function} onComplete (optional) Function to call when animation completes
7363          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7364          * @return {Roo.Element} this
7365          */
7366         autoHeight : function(animate, duration, onComplete, easing){
7367             var oldHeight = this.getHeight();
7368             this.clip();
7369             this.setHeight(1); // force clipping
7370             setTimeout(function(){
7371                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7372                 if(!animate){
7373                     this.setHeight(height);
7374                     this.unclip();
7375                     if(typeof onComplete == "function"){
7376                         onComplete();
7377                     }
7378                 }else{
7379                     this.setHeight(oldHeight); // restore original height
7380                     this.setHeight(height, animate, duration, function(){
7381                         this.unclip();
7382                         if(typeof onComplete == "function") { onComplete(); }
7383                     }.createDelegate(this), easing);
7384                 }
7385             }.createDelegate(this), 0);
7386             return this;
7387         },
7388
7389         /**
7390          * Returns true if this element is an ancestor of the passed element
7391          * @param {HTMLElement/String} el The element to check
7392          * @return {Boolean} True if this element is an ancestor of el, else false
7393          */
7394         contains : function(el){
7395             if(!el){return false;}
7396             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7397         },
7398
7399         /**
7400          * Checks whether the element is currently visible using both visibility and display properties.
7401          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7402          * @return {Boolean} True if the element is currently visible, else false
7403          */
7404         isVisible : function(deep) {
7405             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7406             if(deep !== true || !vis){
7407                 return vis;
7408             }
7409             var p = this.dom.parentNode;
7410             while(p && p.tagName.toLowerCase() != "body"){
7411                 if(!Roo.fly(p, '_isVisible').isVisible()){
7412                     return false;
7413                 }
7414                 p = p.parentNode;
7415             }
7416             return true;
7417         },
7418
7419         /**
7420          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7421          * @param {String} selector The CSS selector
7422          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7423          * @return {CompositeElement/CompositeElementLite} The composite element
7424          */
7425         select : function(selector, unique){
7426             return El.select(selector, unique, this.dom);
7427         },
7428
7429         /**
7430          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7431          * @param {String} selector The CSS selector
7432          * @return {Array} An array of the matched nodes
7433          */
7434         query : function(selector, unique){
7435             return Roo.DomQuery.select(selector, this.dom);
7436         },
7437
7438         /**
7439          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7440          * @param {String} selector The CSS selector
7441          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7442          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7443          */
7444         child : function(selector, returnDom){
7445             var n = Roo.DomQuery.selectNode(selector, this.dom);
7446             return returnDom ? n : Roo.get(n);
7447         },
7448
7449         /**
7450          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7451          * @param {String} selector The CSS selector
7452          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7453          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7454          */
7455         down : function(selector, returnDom){
7456             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7457             return returnDom ? n : Roo.get(n);
7458         },
7459
7460         /**
7461          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7462          * @param {String} group The group the DD object is member of
7463          * @param {Object} config The DD config object
7464          * @param {Object} overrides An object containing methods to override/implement on the DD object
7465          * @return {Roo.dd.DD} The DD object
7466          */
7467         initDD : function(group, config, overrides){
7468             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7469             return Roo.apply(dd, overrides);
7470         },
7471
7472         /**
7473          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7474          * @param {String} group The group the DDProxy object is member of
7475          * @param {Object} config The DDProxy config object
7476          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7477          * @return {Roo.dd.DDProxy} The DDProxy object
7478          */
7479         initDDProxy : function(group, config, overrides){
7480             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7481             return Roo.apply(dd, overrides);
7482         },
7483
7484         /**
7485          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7486          * @param {String} group The group the DDTarget object is member of
7487          * @param {Object} config The DDTarget config object
7488          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7489          * @return {Roo.dd.DDTarget} The DDTarget object
7490          */
7491         initDDTarget : function(group, config, overrides){
7492             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7493             return Roo.apply(dd, overrides);
7494         },
7495
7496         /**
7497          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7498          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7499          * @param {Boolean} visible Whether the element is visible
7500          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7501          * @return {Roo.Element} this
7502          */
7503          setVisible : function(visible, animate){
7504             if(!animate || !A){
7505                 if(this.visibilityMode == El.DISPLAY){
7506                     this.setDisplayed(visible);
7507                 }else{
7508                     this.fixDisplay();
7509                     this.dom.style.visibility = visible ? "visible" : "hidden";
7510                 }
7511             }else{
7512                 // closure for composites
7513                 var dom = this.dom;
7514                 var visMode = this.visibilityMode;
7515                 if(visible){
7516                     this.setOpacity(.01);
7517                     this.setVisible(true);
7518                 }
7519                 this.anim({opacity: { to: (visible?1:0) }},
7520                       this.preanim(arguments, 1),
7521                       null, .35, 'easeIn', function(){
7522                          if(!visible){
7523                              if(visMode == El.DISPLAY){
7524                                  dom.style.display = "none";
7525                              }else{
7526                                  dom.style.visibility = "hidden";
7527                              }
7528                              Roo.get(dom).setOpacity(1);
7529                          }
7530                      });
7531             }
7532             return this;
7533         },
7534
7535         /**
7536          * Returns true if display is not "none"
7537          * @return {Boolean}
7538          */
7539         isDisplayed : function() {
7540             return this.getStyle("display") != "none";
7541         },
7542
7543         /**
7544          * Toggles the element's visibility or display, depending on visibility mode.
7545          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7546          * @return {Roo.Element} this
7547          */
7548         toggle : function(animate){
7549             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7550             return this;
7551         },
7552
7553         /**
7554          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7555          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7556          * @return {Roo.Element} this
7557          */
7558         setDisplayed : function(value) {
7559             if(typeof value == "boolean"){
7560                value = value ? this.originalDisplay : "none";
7561             }
7562             this.setStyle("display", value);
7563             return this;
7564         },
7565
7566         /**
7567          * Tries to focus the element. Any exceptions are caught and ignored.
7568          * @return {Roo.Element} this
7569          */
7570         focus : function() {
7571             try{
7572                 this.dom.focus();
7573             }catch(e){}
7574             return this;
7575         },
7576
7577         /**
7578          * Tries to blur the element. Any exceptions are caught and ignored.
7579          * @return {Roo.Element} this
7580          */
7581         blur : function() {
7582             try{
7583                 this.dom.blur();
7584             }catch(e){}
7585             return this;
7586         },
7587
7588         /**
7589          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7590          * @param {String/Array} className The CSS class to add, or an array of classes
7591          * @return {Roo.Element} this
7592          */
7593         addClass : function(className){
7594             if(className instanceof Array){
7595                 for(var i = 0, len = className.length; i < len; i++) {
7596                     this.addClass(className[i]);
7597                 }
7598             }else{
7599                 if(className && !this.hasClass(className)){
7600                     this.dom.className = this.dom.className + " " + className;
7601                 }
7602             }
7603             return this;
7604         },
7605
7606         /**
7607          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7608          * @param {String/Array} className The CSS class to add, or an array of classes
7609          * @return {Roo.Element} this
7610          */
7611         radioClass : function(className){
7612             var siblings = this.dom.parentNode.childNodes;
7613             for(var i = 0; i < siblings.length; i++) {
7614                 var s = siblings[i];
7615                 if(s.nodeType == 1){
7616                     Roo.get(s).removeClass(className);
7617                 }
7618             }
7619             this.addClass(className);
7620             return this;
7621         },
7622
7623         /**
7624          * Removes one or more CSS classes from the element.
7625          * @param {String/Array} className The CSS class to remove, or an array of classes
7626          * @return {Roo.Element} this
7627          */
7628         removeClass : function(className){
7629             if(!className || !this.dom.className){
7630                 return this;
7631             }
7632             if(className instanceof Array){
7633                 for(var i = 0, len = className.length; i < len; i++) {
7634                     this.removeClass(className[i]);
7635                 }
7636             }else{
7637                 if(this.hasClass(className)){
7638                     var re = this.classReCache[className];
7639                     if (!re) {
7640                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7641                        this.classReCache[className] = re;
7642                     }
7643                     this.dom.className =
7644                         this.dom.className.replace(re, " ");
7645                 }
7646             }
7647             return this;
7648         },
7649
7650         // private
7651         classReCache: {},
7652
7653         /**
7654          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7655          * @param {String} className The CSS class to toggle
7656          * @return {Roo.Element} this
7657          */
7658         toggleClass : function(className){
7659             if(this.hasClass(className)){
7660                 this.removeClass(className);
7661             }else{
7662                 this.addClass(className);
7663             }
7664             return this;
7665         },
7666
7667         /**
7668          * Checks if the specified CSS class exists on this element's DOM node.
7669          * @param {String} className The CSS class to check for
7670          * @return {Boolean} True if the class exists, else false
7671          */
7672         hasClass : function(className){
7673             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7674         },
7675
7676         /**
7677          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7678          * @param {String} oldClassName The CSS class to replace
7679          * @param {String} newClassName The replacement CSS class
7680          * @return {Roo.Element} this
7681          */
7682         replaceClass : function(oldClassName, newClassName){
7683             this.removeClass(oldClassName);
7684             this.addClass(newClassName);
7685             return this;
7686         },
7687
7688         /**
7689          * Returns an object with properties matching the styles requested.
7690          * For example, el.getStyles('color', 'font-size', 'width') might return
7691          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7692          * @param {String} style1 A style name
7693          * @param {String} style2 A style name
7694          * @param {String} etc.
7695          * @return {Object} The style object
7696          */
7697         getStyles : function(){
7698             var a = arguments, len = a.length, r = {};
7699             for(var i = 0; i < len; i++){
7700                 r[a[i]] = this.getStyle(a[i]);
7701             }
7702             return r;
7703         },
7704
7705         /**
7706          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7707          * @param {String} property The style property whose value is returned.
7708          * @return {String} The current value of the style property for this element.
7709          */
7710         getStyle : function(){
7711             return view && view.getComputedStyle ?
7712                 function(prop){
7713                     var el = this.dom, v, cs, camel;
7714                     if(prop == 'float'){
7715                         prop = "cssFloat";
7716                     }
7717                     if(el.style && (v = el.style[prop])){
7718                         return v;
7719                     }
7720                     if(cs = view.getComputedStyle(el, "")){
7721                         if(!(camel = propCache[prop])){
7722                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7723                         }
7724                         return cs[camel];
7725                     }
7726                     return null;
7727                 } :
7728                 function(prop){
7729                     var el = this.dom, v, cs, camel;
7730                     if(prop == 'opacity'){
7731                         if(typeof el.style.filter == 'string'){
7732                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7733                             if(m){
7734                                 var fv = parseFloat(m[1]);
7735                                 if(!isNaN(fv)){
7736                                     return fv ? fv / 100 : 0;
7737                                 }
7738                             }
7739                         }
7740                         return 1;
7741                     }else if(prop == 'float'){
7742                         prop = "styleFloat";
7743                     }
7744                     if(!(camel = propCache[prop])){
7745                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7746                     }
7747                     if(v = el.style[camel]){
7748                         return v;
7749                     }
7750                     if(cs = el.currentStyle){
7751                         return cs[camel];
7752                     }
7753                     return null;
7754                 };
7755         }(),
7756
7757         /**
7758          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7759          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7760          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7761          * @return {Roo.Element} this
7762          */
7763         setStyle : function(prop, value){
7764             if(typeof prop == "string"){
7765                 
7766                 if (prop == 'float') {
7767                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7768                     return this;
7769                 }
7770                 
7771                 var camel;
7772                 if(!(camel = propCache[prop])){
7773                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7774                 }
7775                 
7776                 if(camel == 'opacity') {
7777                     this.setOpacity(value);
7778                 }else{
7779                     this.dom.style[camel] = value;
7780                 }
7781             }else{
7782                 for(var style in prop){
7783                     if(typeof prop[style] != "function"){
7784                        this.setStyle(style, prop[style]);
7785                     }
7786                 }
7787             }
7788             return this;
7789         },
7790
7791         /**
7792          * More flexible version of {@link #setStyle} for setting style properties.
7793          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7794          * a function which returns such a specification.
7795          * @return {Roo.Element} this
7796          */
7797         applyStyles : function(style){
7798             Roo.DomHelper.applyStyles(this.dom, style);
7799             return this;
7800         },
7801
7802         /**
7803           * 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).
7804           * @return {Number} The X position of the element
7805           */
7806         getX : function(){
7807             return D.getX(this.dom);
7808         },
7809
7810         /**
7811           * 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).
7812           * @return {Number} The Y position of the element
7813           */
7814         getY : function(){
7815             return D.getY(this.dom);
7816         },
7817
7818         /**
7819           * 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).
7820           * @return {Array} The XY position of the element
7821           */
7822         getXY : function(){
7823             return D.getXY(this.dom);
7824         },
7825
7826         /**
7827          * 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).
7828          * @param {Number} The X position of the element
7829          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7830          * @return {Roo.Element} this
7831          */
7832         setX : function(x, animate){
7833             if(!animate || !A){
7834                 D.setX(this.dom, x);
7835             }else{
7836                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7837             }
7838             return this;
7839         },
7840
7841         /**
7842          * 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).
7843          * @param {Number} The Y position of the element
7844          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7845          * @return {Roo.Element} this
7846          */
7847         setY : function(y, animate){
7848             if(!animate || !A){
7849                 D.setY(this.dom, y);
7850             }else{
7851                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7852             }
7853             return this;
7854         },
7855
7856         /**
7857          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7858          * @param {String} left The left CSS property value
7859          * @return {Roo.Element} this
7860          */
7861         setLeft : function(left){
7862             this.setStyle("left", this.addUnits(left));
7863             return this;
7864         },
7865
7866         /**
7867          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7868          * @param {String} top The top CSS property value
7869          * @return {Roo.Element} this
7870          */
7871         setTop : function(top){
7872             this.setStyle("top", this.addUnits(top));
7873             return this;
7874         },
7875
7876         /**
7877          * Sets the element's CSS right style.
7878          * @param {String} right The right CSS property value
7879          * @return {Roo.Element} this
7880          */
7881         setRight : function(right){
7882             this.setStyle("right", this.addUnits(right));
7883             return this;
7884         },
7885
7886         /**
7887          * Sets the element's CSS bottom style.
7888          * @param {String} bottom The bottom CSS property value
7889          * @return {Roo.Element} this
7890          */
7891         setBottom : function(bottom){
7892             this.setStyle("bottom", this.addUnits(bottom));
7893             return this;
7894         },
7895
7896         /**
7897          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7898          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7899          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7900          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7901          * @return {Roo.Element} this
7902          */
7903         setXY : function(pos, animate){
7904             if(!animate || !A){
7905                 D.setXY(this.dom, pos);
7906             }else{
7907                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7908             }
7909             return this;
7910         },
7911
7912         /**
7913          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7914          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7915          * @param {Number} x X value for new position (coordinates are page-based)
7916          * @param {Number} y Y value for new position (coordinates are page-based)
7917          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7918          * @return {Roo.Element} this
7919          */
7920         setLocation : function(x, y, animate){
7921             this.setXY([x, y], this.preanim(arguments, 2));
7922             return this;
7923         },
7924
7925         /**
7926          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7927          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7928          * @param {Number} x X value for new position (coordinates are page-based)
7929          * @param {Number} y Y value for new position (coordinates are page-based)
7930          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7931          * @return {Roo.Element} this
7932          */
7933         moveTo : function(x, y, animate){
7934             this.setXY([x, y], this.preanim(arguments, 2));
7935             return this;
7936         },
7937
7938         /**
7939          * Returns the region of the given element.
7940          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7941          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7942          */
7943         getRegion : function(){
7944             return D.getRegion(this.dom);
7945         },
7946
7947         /**
7948          * Returns the offset height of the element
7949          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7950          * @return {Number} The element's height
7951          */
7952         getHeight : function(contentHeight){
7953             var h = this.dom.offsetHeight || 0;
7954             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7955         },
7956
7957         /**
7958          * Returns the offset width of the element
7959          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7960          * @return {Number} The element's width
7961          */
7962         getWidth : function(contentWidth){
7963             var w = this.dom.offsetWidth || 0;
7964             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7965         },
7966
7967         /**
7968          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7969          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7970          * if a height has not been set using CSS.
7971          * @return {Number}
7972          */
7973         getComputedHeight : function(){
7974             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7975             if(!h){
7976                 h = parseInt(this.getStyle('height'), 10) || 0;
7977                 if(!this.isBorderBox()){
7978                     h += this.getFrameWidth('tb');
7979                 }
7980             }
7981             return h;
7982         },
7983
7984         /**
7985          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7986          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7987          * if a width has not been set using CSS.
7988          * @return {Number}
7989          */
7990         getComputedWidth : function(){
7991             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7992             if(!w){
7993                 w = parseInt(this.getStyle('width'), 10) || 0;
7994                 if(!this.isBorderBox()){
7995                     w += this.getFrameWidth('lr');
7996                 }
7997             }
7998             return w;
7999         },
8000
8001         /**
8002          * Returns the size of the element.
8003          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8004          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8005          */
8006         getSize : function(contentSize){
8007             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8008         },
8009
8010         /**
8011          * Returns the width and height of the viewport.
8012          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8013          */
8014         getViewSize : function(){
8015             var d = this.dom, doc = document, aw = 0, ah = 0;
8016             if(d == doc || d == doc.body){
8017                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8018             }else{
8019                 return {
8020                     width : d.clientWidth,
8021                     height: d.clientHeight
8022                 };
8023             }
8024         },
8025
8026         /**
8027          * Returns the value of the "value" attribute
8028          * @param {Boolean} asNumber true to parse the value as a number
8029          * @return {String/Number}
8030          */
8031         getValue : function(asNumber){
8032             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8033         },
8034
8035         // private
8036         adjustWidth : function(width){
8037             if(typeof width == "number"){
8038                 if(this.autoBoxAdjust && !this.isBorderBox()){
8039                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8040                 }
8041                 if(width < 0){
8042                     width = 0;
8043                 }
8044             }
8045             return width;
8046         },
8047
8048         // private
8049         adjustHeight : function(height){
8050             if(typeof height == "number"){
8051                if(this.autoBoxAdjust && !this.isBorderBox()){
8052                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8053                }
8054                if(height < 0){
8055                    height = 0;
8056                }
8057             }
8058             return height;
8059         },
8060
8061         /**
8062          * Set the width of the element
8063          * @param {Number} width The new width
8064          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8065          * @return {Roo.Element} this
8066          */
8067         setWidth : function(width, animate){
8068             width = this.adjustWidth(width);
8069             if(!animate || !A){
8070                 this.dom.style.width = this.addUnits(width);
8071             }else{
8072                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8073             }
8074             return this;
8075         },
8076
8077         /**
8078          * Set the height of the element
8079          * @param {Number} height The new height
8080          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8081          * @return {Roo.Element} this
8082          */
8083          setHeight : function(height, animate){
8084             height = this.adjustHeight(height);
8085             if(!animate || !A){
8086                 this.dom.style.height = this.addUnits(height);
8087             }else{
8088                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8089             }
8090             return this;
8091         },
8092
8093         /**
8094          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8095          * @param {Number} width The new width
8096          * @param {Number} height The new height
8097          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8098          * @return {Roo.Element} this
8099          */
8100          setSize : function(width, height, animate){
8101             if(typeof width == "object"){ // in case of object from getSize()
8102                 height = width.height; width = width.width;
8103             }
8104             width = this.adjustWidth(width); height = this.adjustHeight(height);
8105             if(!animate || !A){
8106                 this.dom.style.width = this.addUnits(width);
8107                 this.dom.style.height = this.addUnits(height);
8108             }else{
8109                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8110             }
8111             return this;
8112         },
8113
8114         /**
8115          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8116          * @param {Number} x X value for new position (coordinates are page-based)
8117          * @param {Number} y Y value for new position (coordinates are page-based)
8118          * @param {Number} width The new width
8119          * @param {Number} height The new height
8120          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8121          * @return {Roo.Element} this
8122          */
8123         setBounds : function(x, y, width, height, animate){
8124             if(!animate || !A){
8125                 this.setSize(width, height);
8126                 this.setLocation(x, y);
8127             }else{
8128                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8129                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8130                               this.preanim(arguments, 4), 'motion');
8131             }
8132             return this;
8133         },
8134
8135         /**
8136          * 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.
8137          * @param {Roo.lib.Region} region The region to fill
8138          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8139          * @return {Roo.Element} this
8140          */
8141         setRegion : function(region, animate){
8142             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8143             return this;
8144         },
8145
8146         /**
8147          * Appends an event handler
8148          *
8149          * @param {String}   eventName     The type of event to append
8150          * @param {Function} fn        The method the event invokes
8151          * @param {Object} scope       (optional) The scope (this object) of the fn
8152          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8153          */
8154         addListener : function(eventName, fn, scope, options){
8155             if (this.dom) {
8156                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8157             }
8158         },
8159
8160         /**
8161          * Removes an event handler from this element
8162          * @param {String} eventName the type of event to remove
8163          * @param {Function} fn the method the event invokes
8164          * @return {Roo.Element} this
8165          */
8166         removeListener : function(eventName, fn){
8167             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8168             return this;
8169         },
8170
8171         /**
8172          * Removes all previous added listeners from this element
8173          * @return {Roo.Element} this
8174          */
8175         removeAllListeners : function(){
8176             E.purgeElement(this.dom);
8177             return this;
8178         },
8179
8180         relayEvent : function(eventName, observable){
8181             this.on(eventName, function(e){
8182                 observable.fireEvent(eventName, e);
8183             });
8184         },
8185
8186         /**
8187          * Set the opacity of the element
8188          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8189          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8190          * @return {Roo.Element} this
8191          */
8192          setOpacity : function(opacity, animate){
8193             if(!animate || !A){
8194                 var s = this.dom.style;
8195                 if(Roo.isIE){
8196                     s.zoom = 1;
8197                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8198                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8199                 }else{
8200                     s.opacity = opacity;
8201                 }
8202             }else{
8203                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8204             }
8205             return this;
8206         },
8207
8208         /**
8209          * Gets the left X coordinate
8210          * @param {Boolean} local True to get the local css position instead of page coordinate
8211          * @return {Number}
8212          */
8213         getLeft : function(local){
8214             if(!local){
8215                 return this.getX();
8216             }else{
8217                 return parseInt(this.getStyle("left"), 10) || 0;
8218             }
8219         },
8220
8221         /**
8222          * Gets the right X coordinate of the element (element X position + element width)
8223          * @param {Boolean} local True to get the local css position instead of page coordinate
8224          * @return {Number}
8225          */
8226         getRight : function(local){
8227             if(!local){
8228                 return this.getX() + this.getWidth();
8229             }else{
8230                 return (this.getLeft(true) + this.getWidth()) || 0;
8231             }
8232         },
8233
8234         /**
8235          * Gets the top Y coordinate
8236          * @param {Boolean} local True to get the local css position instead of page coordinate
8237          * @return {Number}
8238          */
8239         getTop : function(local) {
8240             if(!local){
8241                 return this.getY();
8242             }else{
8243                 return parseInt(this.getStyle("top"), 10) || 0;
8244             }
8245         },
8246
8247         /**
8248          * Gets the bottom Y coordinate of the element (element Y position + element height)
8249          * @param {Boolean} local True to get the local css position instead of page coordinate
8250          * @return {Number}
8251          */
8252         getBottom : function(local){
8253             if(!local){
8254                 return this.getY() + this.getHeight();
8255             }else{
8256                 return (this.getTop(true) + this.getHeight()) || 0;
8257             }
8258         },
8259
8260         /**
8261         * Initializes positioning on this element. If a desired position is not passed, it will make the
8262         * the element positioned relative IF it is not already positioned.
8263         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8264         * @param {Number} zIndex (optional) The zIndex to apply
8265         * @param {Number} x (optional) Set the page X position
8266         * @param {Number} y (optional) Set the page Y position
8267         */
8268         position : function(pos, zIndex, x, y){
8269             if(!pos){
8270                if(this.getStyle('position') == 'static'){
8271                    this.setStyle('position', 'relative');
8272                }
8273             }else{
8274                 this.setStyle("position", pos);
8275             }
8276             if(zIndex){
8277                 this.setStyle("z-index", zIndex);
8278             }
8279             if(x !== undefined && y !== undefined){
8280                 this.setXY([x, y]);
8281             }else if(x !== undefined){
8282                 this.setX(x);
8283             }else if(y !== undefined){
8284                 this.setY(y);
8285             }
8286         },
8287
8288         /**
8289         * Clear positioning back to the default when the document was loaded
8290         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8291         * @return {Roo.Element} this
8292          */
8293         clearPositioning : function(value){
8294             value = value ||'';
8295             this.setStyle({
8296                 "left": value,
8297                 "right": value,
8298                 "top": value,
8299                 "bottom": value,
8300                 "z-index": "",
8301                 "position" : "static"
8302             });
8303             return this;
8304         },
8305
8306         /**
8307         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8308         * snapshot before performing an update and then restoring the element.
8309         * @return {Object}
8310         */
8311         getPositioning : function(){
8312             var l = this.getStyle("left");
8313             var t = this.getStyle("top");
8314             return {
8315                 "position" : this.getStyle("position"),
8316                 "left" : l,
8317                 "right" : l ? "" : this.getStyle("right"),
8318                 "top" : t,
8319                 "bottom" : t ? "" : this.getStyle("bottom"),
8320                 "z-index" : this.getStyle("z-index")
8321             };
8322         },
8323
8324         /**
8325          * Gets the width of the border(s) for the specified side(s)
8326          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8327          * passing lr would get the border (l)eft width + the border (r)ight width.
8328          * @return {Number} The width of the sides passed added together
8329          */
8330         getBorderWidth : function(side){
8331             return this.addStyles(side, El.borders);
8332         },
8333
8334         /**
8335          * Gets the width of the padding(s) for the specified side(s)
8336          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8337          * passing lr would get the padding (l)eft + the padding (r)ight.
8338          * @return {Number} The padding of the sides passed added together
8339          */
8340         getPadding : function(side){
8341             return this.addStyles(side, El.paddings);
8342         },
8343
8344         /**
8345         * Set positioning with an object returned by getPositioning().
8346         * @param {Object} posCfg
8347         * @return {Roo.Element} this
8348          */
8349         setPositioning : function(pc){
8350             this.applyStyles(pc);
8351             if(pc.right == "auto"){
8352                 this.dom.style.right = "";
8353             }
8354             if(pc.bottom == "auto"){
8355                 this.dom.style.bottom = "";
8356             }
8357             return this;
8358         },
8359
8360         // private
8361         fixDisplay : function(){
8362             if(this.getStyle("display") == "none"){
8363                 this.setStyle("visibility", "hidden");
8364                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8365                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8366                     this.setStyle("display", "block");
8367                 }
8368             }
8369         },
8370
8371         /**
8372          * Quick set left and top adding default units
8373          * @param {String} left The left CSS property value
8374          * @param {String} top The top CSS property value
8375          * @return {Roo.Element} this
8376          */
8377          setLeftTop : function(left, top){
8378             this.dom.style.left = this.addUnits(left);
8379             this.dom.style.top = this.addUnits(top);
8380             return this;
8381         },
8382
8383         /**
8384          * Move this element relative to its current position.
8385          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8386          * @param {Number} distance How far to move the element in pixels
8387          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8388          * @return {Roo.Element} this
8389          */
8390          move : function(direction, distance, animate){
8391             var xy = this.getXY();
8392             direction = direction.toLowerCase();
8393             switch(direction){
8394                 case "l":
8395                 case "left":
8396                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8397                     break;
8398                case "r":
8399                case "right":
8400                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8401                     break;
8402                case "t":
8403                case "top":
8404                case "up":
8405                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8406                     break;
8407                case "b":
8408                case "bottom":
8409                case "down":
8410                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8411                     break;
8412             }
8413             return this;
8414         },
8415
8416         /**
8417          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8418          * @return {Roo.Element} this
8419          */
8420         clip : function(){
8421             if(!this.isClipped){
8422                this.isClipped = true;
8423                this.originalClip = {
8424                    "o": this.getStyle("overflow"),
8425                    "x": this.getStyle("overflow-x"),
8426                    "y": this.getStyle("overflow-y")
8427                };
8428                this.setStyle("overflow", "hidden");
8429                this.setStyle("overflow-x", "hidden");
8430                this.setStyle("overflow-y", "hidden");
8431             }
8432             return this;
8433         },
8434
8435         /**
8436          *  Return clipping (overflow) to original clipping before clip() was called
8437          * @return {Roo.Element} this
8438          */
8439         unclip : function(){
8440             if(this.isClipped){
8441                 this.isClipped = false;
8442                 var o = this.originalClip;
8443                 if(o.o){this.setStyle("overflow", o.o);}
8444                 if(o.x){this.setStyle("overflow-x", o.x);}
8445                 if(o.y){this.setStyle("overflow-y", o.y);}
8446             }
8447             return this;
8448         },
8449
8450
8451         /**
8452          * Gets the x,y coordinates specified by the anchor position on the element.
8453          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8454          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8455          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8456          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8457          * @return {Array} [x, y] An array containing the element's x and y coordinates
8458          */
8459         getAnchorXY : function(anchor, local, s){
8460             //Passing a different size is useful for pre-calculating anchors,
8461             //especially for anchored animations that change the el size.
8462
8463             var w, h, vp = false;
8464             if(!s){
8465                 var d = this.dom;
8466                 if(d == document.body || d == document){
8467                     vp = true;
8468                     w = D.getViewWidth(); h = D.getViewHeight();
8469                 }else{
8470                     w = this.getWidth(); h = this.getHeight();
8471                 }
8472             }else{
8473                 w = s.width;  h = s.height;
8474             }
8475             var x = 0, y = 0, r = Math.round;
8476             switch((anchor || "tl").toLowerCase()){
8477                 case "c":
8478                     x = r(w*.5);
8479                     y = r(h*.5);
8480                 break;
8481                 case "t":
8482                     x = r(w*.5);
8483                     y = 0;
8484                 break;
8485                 case "l":
8486                     x = 0;
8487                     y = r(h*.5);
8488                 break;
8489                 case "r":
8490                     x = w;
8491                     y = r(h*.5);
8492                 break;
8493                 case "b":
8494                     x = r(w*.5);
8495                     y = h;
8496                 break;
8497                 case "tl":
8498                     x = 0;
8499                     y = 0;
8500                 break;
8501                 case "bl":
8502                     x = 0;
8503                     y = h;
8504                 break;
8505                 case "br":
8506                     x = w;
8507                     y = h;
8508                 break;
8509                 case "tr":
8510                     x = w;
8511                     y = 0;
8512                 break;
8513             }
8514             if(local === true){
8515                 return [x, y];
8516             }
8517             if(vp){
8518                 var sc = this.getScroll();
8519                 return [x + sc.left, y + sc.top];
8520             }
8521             //Add the element's offset xy
8522             var o = this.getXY();
8523             return [x+o[0], y+o[1]];
8524         },
8525
8526         /**
8527          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8528          * supported position values.
8529          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8530          * @param {String} position The position to align to.
8531          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8532          * @return {Array} [x, y]
8533          */
8534         getAlignToXY : function(el, p, o){
8535             el = Roo.get(el);
8536             var d = this.dom;
8537             if(!el.dom){
8538                 throw "Element.alignTo with an element that doesn't exist";
8539             }
8540             var c = false; //constrain to viewport
8541             var p1 = "", p2 = "";
8542             o = o || [0,0];
8543
8544             if(!p){
8545                 p = "tl-bl";
8546             }else if(p == "?"){
8547                 p = "tl-bl?";
8548             }else if(p.indexOf("-") == -1){
8549                 p = "tl-" + p;
8550             }
8551             p = p.toLowerCase();
8552             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8553             if(!m){
8554                throw "Element.alignTo with an invalid alignment " + p;
8555             }
8556             p1 = m[1]; p2 = m[2]; c = !!m[3];
8557
8558             //Subtract the aligned el's internal xy from the target's offset xy
8559             //plus custom offset to get the aligned el's new offset xy
8560             var a1 = this.getAnchorXY(p1, true);
8561             var a2 = el.getAnchorXY(p2, false);
8562             var x = a2[0] - a1[0] + o[0];
8563             var y = a2[1] - a1[1] + o[1];
8564             if(c){
8565                 //constrain the aligned el to viewport if necessary
8566                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8567                 // 5px of margin for ie
8568                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8569
8570                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8571                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8572                 //otherwise swap the aligned el to the opposite border of the target.
8573                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8574                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8575                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8576                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8577
8578                var doc = document;
8579                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8580                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8581
8582                if((x+w) > dw + scrollX){
8583                     x = swapX ? r.left-w : dw+scrollX-w;
8584                 }
8585                if(x < scrollX){
8586                    x = swapX ? r.right : scrollX;
8587                }
8588                if((y+h) > dh + scrollY){
8589                     y = swapY ? r.top-h : dh+scrollY-h;
8590                 }
8591                if (y < scrollY){
8592                    y = swapY ? r.bottom : scrollY;
8593                }
8594             }
8595             return [x,y];
8596         },
8597
8598         // private
8599         getConstrainToXY : function(){
8600             var os = {top:0, left:0, bottom:0, right: 0};
8601
8602             return function(el, local, offsets, proposedXY){
8603                 el = Roo.get(el);
8604                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8605
8606                 var vw, vh, vx = 0, vy = 0;
8607                 if(el.dom == document.body || el.dom == document){
8608                     vw = Roo.lib.Dom.getViewWidth();
8609                     vh = Roo.lib.Dom.getViewHeight();
8610                 }else{
8611                     vw = el.dom.clientWidth;
8612                     vh = el.dom.clientHeight;
8613                     if(!local){
8614                         var vxy = el.getXY();
8615                         vx = vxy[0];
8616                         vy = vxy[1];
8617                     }
8618                 }
8619
8620                 var s = el.getScroll();
8621
8622                 vx += offsets.left + s.left;
8623                 vy += offsets.top + s.top;
8624
8625                 vw -= offsets.right;
8626                 vh -= offsets.bottom;
8627
8628                 var vr = vx+vw;
8629                 var vb = vy+vh;
8630
8631                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8632                 var x = xy[0], y = xy[1];
8633                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8634
8635                 // only move it if it needs it
8636                 var moved = false;
8637
8638                 // first validate right/bottom
8639                 if((x + w) > vr){
8640                     x = vr - w;
8641                     moved = true;
8642                 }
8643                 if((y + h) > vb){
8644                     y = vb - h;
8645                     moved = true;
8646                 }
8647                 // then make sure top/left isn't negative
8648                 if(x < vx){
8649                     x = vx;
8650                     moved = true;
8651                 }
8652                 if(y < vy){
8653                     y = vy;
8654                     moved = true;
8655                 }
8656                 return moved ? [x, y] : false;
8657             };
8658         }(),
8659
8660         // private
8661         adjustForConstraints : function(xy, parent, offsets){
8662             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8663         },
8664
8665         /**
8666          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8667          * document it aligns it to the viewport.
8668          * The position parameter is optional, and can be specified in any one of the following formats:
8669          * <ul>
8670          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8671          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8672          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8673          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8674          *   <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
8675          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8676          * </ul>
8677          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8678          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8679          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8680          * that specified in order to enforce the viewport constraints.
8681          * Following are all of the supported anchor positions:
8682     <pre>
8683     Value  Description
8684     -----  -----------------------------
8685     tl     The top left corner (default)
8686     t      The center of the top edge
8687     tr     The top right corner
8688     l      The center of the left edge
8689     c      In the center of the element
8690     r      The center of the right edge
8691     bl     The bottom left corner
8692     b      The center of the bottom edge
8693     br     The bottom right corner
8694     </pre>
8695     Example Usage:
8696     <pre><code>
8697     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8698     el.alignTo("other-el");
8699
8700     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8701     el.alignTo("other-el", "tr?");
8702
8703     // align the bottom right corner of el with the center left edge of other-el
8704     el.alignTo("other-el", "br-l?");
8705
8706     // align the center of el with the bottom left corner of other-el and
8707     // adjust the x position by -6 pixels (and the y position by 0)
8708     el.alignTo("other-el", "c-bl", [-6, 0]);
8709     </code></pre>
8710          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8711          * @param {String} position The position to align to.
8712          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8713          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8714          * @return {Roo.Element} this
8715          */
8716         alignTo : function(element, position, offsets, animate){
8717             var xy = this.getAlignToXY(element, position, offsets);
8718             this.setXY(xy, this.preanim(arguments, 3));
8719             return this;
8720         },
8721
8722         /**
8723          * Anchors an element to another element and realigns it when the window is resized.
8724          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8725          * @param {String} position The position to align to.
8726          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8727          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8728          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8729          * is a number, it is used as the buffer delay (defaults to 50ms).
8730          * @param {Function} callback The function to call after the animation finishes
8731          * @return {Roo.Element} this
8732          */
8733         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8734             var action = function(){
8735                 this.alignTo(el, alignment, offsets, animate);
8736                 Roo.callback(callback, this);
8737             };
8738             Roo.EventManager.onWindowResize(action, this);
8739             var tm = typeof monitorScroll;
8740             if(tm != 'undefined'){
8741                 Roo.EventManager.on(window, 'scroll', action, this,
8742                     {buffer: tm == 'number' ? monitorScroll : 50});
8743             }
8744             action.call(this); // align immediately
8745             return this;
8746         },
8747         /**
8748          * Clears any opacity settings from this element. Required in some cases for IE.
8749          * @return {Roo.Element} this
8750          */
8751         clearOpacity : function(){
8752             if (window.ActiveXObject) {
8753                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8754                     this.dom.style.filter = "";
8755                 }
8756             } else {
8757                 this.dom.style.opacity = "";
8758                 this.dom.style["-moz-opacity"] = "";
8759                 this.dom.style["-khtml-opacity"] = "";
8760             }
8761             return this;
8762         },
8763
8764         /**
8765          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8766          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8767          * @return {Roo.Element} this
8768          */
8769         hide : function(animate){
8770             this.setVisible(false, this.preanim(arguments, 0));
8771             return this;
8772         },
8773
8774         /**
8775         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8776         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777          * @return {Roo.Element} this
8778          */
8779         show : function(animate){
8780             this.setVisible(true, this.preanim(arguments, 0));
8781             return this;
8782         },
8783
8784         /**
8785          * @private Test if size has a unit, otherwise appends the default
8786          */
8787         addUnits : function(size){
8788             return Roo.Element.addUnits(size, this.defaultUnit);
8789         },
8790
8791         /**
8792          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8793          * @return {Roo.Element} this
8794          */
8795         beginMeasure : function(){
8796             var el = this.dom;
8797             if(el.offsetWidth || el.offsetHeight){
8798                 return this; // offsets work already
8799             }
8800             var changed = [];
8801             var p = this.dom, b = document.body; // start with this element
8802             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8803                 var pe = Roo.get(p);
8804                 if(pe.getStyle('display') == 'none'){
8805                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8806                     p.style.visibility = "hidden";
8807                     p.style.display = "block";
8808                 }
8809                 p = p.parentNode;
8810             }
8811             this._measureChanged = changed;
8812             return this;
8813
8814         },
8815
8816         /**
8817          * Restores displays to before beginMeasure was called
8818          * @return {Roo.Element} this
8819          */
8820         endMeasure : function(){
8821             var changed = this._measureChanged;
8822             if(changed){
8823                 for(var i = 0, len = changed.length; i < len; i++) {
8824                     var r = changed[i];
8825                     r.el.style.visibility = r.visibility;
8826                     r.el.style.display = "none";
8827                 }
8828                 this._measureChanged = null;
8829             }
8830             return this;
8831         },
8832
8833         /**
8834         * Update the innerHTML of this element, optionally searching for and processing scripts
8835         * @param {String} html The new HTML
8836         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8837         * @param {Function} callback For async script loading you can be noticed when the update completes
8838         * @return {Roo.Element} this
8839          */
8840         update : function(html, loadScripts, callback){
8841             if(typeof html == "undefined"){
8842                 html = "";
8843             }
8844             if(loadScripts !== true){
8845                 this.dom.innerHTML = html;
8846                 if(typeof callback == "function"){
8847                     callback();
8848                 }
8849                 return this;
8850             }
8851             var id = Roo.id();
8852             var dom = this.dom;
8853
8854             html += '<span id="' + id + '"></span>';
8855
8856             E.onAvailable(id, function(){
8857                 var hd = document.getElementsByTagName("head")[0];
8858                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8859                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8860                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8861
8862                 var match;
8863                 while(match = re.exec(html)){
8864                     var attrs = match[1];
8865                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8866                     if(srcMatch && srcMatch[2]){
8867                        var s = document.createElement("script");
8868                        s.src = srcMatch[2];
8869                        var typeMatch = attrs.match(typeRe);
8870                        if(typeMatch && typeMatch[2]){
8871                            s.type = typeMatch[2];
8872                        }
8873                        hd.appendChild(s);
8874                     }else if(match[2] && match[2].length > 0){
8875                         if(window.execScript) {
8876                            window.execScript(match[2]);
8877                         } else {
8878                             /**
8879                              * eval:var:id
8880                              * eval:var:dom
8881                              * eval:var:html
8882                              * 
8883                              */
8884                            window.eval(match[2]);
8885                         }
8886                     }
8887                 }
8888                 var el = document.getElementById(id);
8889                 if(el){el.parentNode.removeChild(el);}
8890                 if(typeof callback == "function"){
8891                     callback();
8892                 }
8893             });
8894             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8895             return this;
8896         },
8897
8898         /**
8899          * Direct access to the UpdateManager update() method (takes the same parameters).
8900          * @param {String/Function} url The url for this request or a function to call to get the url
8901          * @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}
8902          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8903          * @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.
8904          * @return {Roo.Element} this
8905          */
8906         load : function(){
8907             var um = this.getUpdateManager();
8908             um.update.apply(um, arguments);
8909             return this;
8910         },
8911
8912         /**
8913         * Gets this element's UpdateManager
8914         * @return {Roo.UpdateManager} The UpdateManager
8915         */
8916         getUpdateManager : function(){
8917             if(!this.updateManager){
8918                 this.updateManager = new Roo.UpdateManager(this);
8919             }
8920             return this.updateManager;
8921         },
8922
8923         /**
8924          * Disables text selection for this element (normalized across browsers)
8925          * @return {Roo.Element} this
8926          */
8927         unselectable : function(){
8928             this.dom.unselectable = "on";
8929             this.swallowEvent("selectstart", true);
8930             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8931             this.addClass("x-unselectable");
8932             return this;
8933         },
8934
8935         /**
8936         * Calculates the x, y to center this element on the screen
8937         * @return {Array} The x, y values [x, y]
8938         */
8939         getCenterXY : function(){
8940             return this.getAlignToXY(document, 'c-c');
8941         },
8942
8943         /**
8944         * Centers the Element in either the viewport, or another Element.
8945         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8946         */
8947         center : function(centerIn){
8948             this.alignTo(centerIn || document, 'c-c');
8949             return this;
8950         },
8951
8952         /**
8953          * Tests various css rules/browsers to determine if this element uses a border box
8954          * @return {Boolean}
8955          */
8956         isBorderBox : function(){
8957             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8958         },
8959
8960         /**
8961          * Return a box {x, y, width, height} that can be used to set another elements
8962          * size/location to match this element.
8963          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8964          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8965          * @return {Object} box An object in the format {x, y, width, height}
8966          */
8967         getBox : function(contentBox, local){
8968             var xy;
8969             if(!local){
8970                 xy = this.getXY();
8971             }else{
8972                 var left = parseInt(this.getStyle("left"), 10) || 0;
8973                 var top = parseInt(this.getStyle("top"), 10) || 0;
8974                 xy = [left, top];
8975             }
8976             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8977             if(!contentBox){
8978                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8979             }else{
8980                 var l = this.getBorderWidth("l")+this.getPadding("l");
8981                 var r = this.getBorderWidth("r")+this.getPadding("r");
8982                 var t = this.getBorderWidth("t")+this.getPadding("t");
8983                 var b = this.getBorderWidth("b")+this.getPadding("b");
8984                 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)};
8985             }
8986             bx.right = bx.x + bx.width;
8987             bx.bottom = bx.y + bx.height;
8988             return bx;
8989         },
8990
8991         /**
8992          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8993          for more information about the sides.
8994          * @param {String} sides
8995          * @return {Number}
8996          */
8997         getFrameWidth : function(sides, onlyContentBox){
8998             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8999         },
9000
9001         /**
9002          * 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.
9003          * @param {Object} box The box to fill {x, y, width, height}
9004          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9005          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9006          * @return {Roo.Element} this
9007          */
9008         setBox : function(box, adjust, animate){
9009             var w = box.width, h = box.height;
9010             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9011                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9012                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9013             }
9014             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9015             return this;
9016         },
9017
9018         /**
9019          * Forces the browser to repaint this element
9020          * @return {Roo.Element} this
9021          */
9022          repaint : function(){
9023             var dom = this.dom;
9024             this.addClass("x-repaint");
9025             setTimeout(function(){
9026                 Roo.get(dom).removeClass("x-repaint");
9027             }, 1);
9028             return this;
9029         },
9030
9031         /**
9032          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9033          * then it returns the calculated width of the sides (see getPadding)
9034          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9035          * @return {Object/Number}
9036          */
9037         getMargins : function(side){
9038             if(!side){
9039                 return {
9040                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9041                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9042                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9043                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9044                 };
9045             }else{
9046                 return this.addStyles(side, El.margins);
9047              }
9048         },
9049
9050         // private
9051         addStyles : function(sides, styles){
9052             var val = 0, v, w;
9053             for(var i = 0, len = sides.length; i < len; i++){
9054                 v = this.getStyle(styles[sides.charAt(i)]);
9055                 if(v){
9056                      w = parseInt(v, 10);
9057                      if(w){ val += w; }
9058                 }
9059             }
9060             return val;
9061         },
9062
9063         /**
9064          * Creates a proxy element of this element
9065          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9066          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9067          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9068          * @return {Roo.Element} The new proxy element
9069          */
9070         createProxy : function(config, renderTo, matchBox){
9071             if(renderTo){
9072                 renderTo = Roo.getDom(renderTo);
9073             }else{
9074                 renderTo = document.body;
9075             }
9076             config = typeof config == "object" ?
9077                 config : {tag : "div", cls: config};
9078             var proxy = Roo.DomHelper.append(renderTo, config, true);
9079             if(matchBox){
9080                proxy.setBox(this.getBox());
9081             }
9082             return proxy;
9083         },
9084
9085         /**
9086          * Puts a mask over this element to disable user interaction. Requires core.css.
9087          * This method can only be applied to elements which accept child nodes.
9088          * @param {String} msg (optional) A message to display in the mask
9089          * @param {String} msgCls (optional) A css class to apply to the msg element
9090          * @return {Element} The mask  element
9091          */
9092         mask : function(msg, msgCls)
9093         {
9094             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9095                 this.setStyle("position", "relative");
9096             }
9097             if(!this._mask){
9098                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9099             }
9100             this.addClass("x-masked");
9101             this._mask.setDisplayed(true);
9102             
9103             // we wander
9104             var z = 0;
9105             var dom = this.dom;
9106             while (dom && dom.style) {
9107                 if (!isNaN(parseInt(dom.style.zIndex))) {
9108                     z = Math.max(z, parseInt(dom.style.zIndex));
9109                 }
9110                 dom = dom.parentNode;
9111             }
9112             // if we are masking the body - then it hides everything..
9113             if (this.dom == document.body) {
9114                 z = 1000000;
9115                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9116                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9117             }
9118            
9119             if(typeof msg == 'string'){
9120                 if(!this._maskMsg){
9121                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9122                 }
9123                 var mm = this._maskMsg;
9124                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9125                 if (mm.dom.firstChild) { // weird IE issue?
9126                     mm.dom.firstChild.innerHTML = msg;
9127                 }
9128                 mm.setDisplayed(true);
9129                 mm.center(this);
9130                 mm.setStyle('z-index', z + 102);
9131             }
9132             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9133                 this._mask.setHeight(this.getHeight());
9134             }
9135             this._mask.setStyle('z-index', z + 100);
9136             
9137             return this._mask;
9138         },
9139
9140         /**
9141          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9142          * it is cached for reuse.
9143          */
9144         unmask : function(removeEl){
9145             if(this._mask){
9146                 if(removeEl === true){
9147                     this._mask.remove();
9148                     delete this._mask;
9149                     if(this._maskMsg){
9150                         this._maskMsg.remove();
9151                         delete this._maskMsg;
9152                     }
9153                 }else{
9154                     this._mask.setDisplayed(false);
9155                     if(this._maskMsg){
9156                         this._maskMsg.setDisplayed(false);
9157                     }
9158                 }
9159             }
9160             this.removeClass("x-masked");
9161         },
9162
9163         /**
9164          * Returns true if this element is masked
9165          * @return {Boolean}
9166          */
9167         isMasked : function(){
9168             return this._mask && this._mask.isVisible();
9169         },
9170
9171         /**
9172          * Creates an iframe shim for this element to keep selects and other windowed objects from
9173          * showing through.
9174          * @return {Roo.Element} The new shim element
9175          */
9176         createShim : function(){
9177             var el = document.createElement('iframe');
9178             el.frameBorder = 'no';
9179             el.className = 'roo-shim';
9180             if(Roo.isIE && Roo.isSecure){
9181                 el.src = Roo.SSL_SECURE_URL;
9182             }
9183             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9184             shim.autoBoxAdjust = false;
9185             return shim;
9186         },
9187
9188         /**
9189          * Removes this element from the DOM and deletes it from the cache
9190          */
9191         remove : function(){
9192             if(this.dom.parentNode){
9193                 this.dom.parentNode.removeChild(this.dom);
9194             }
9195             delete El.cache[this.dom.id];
9196         },
9197
9198         /**
9199          * Sets up event handlers to add and remove a css class when the mouse is over this element
9200          * @param {String} className
9201          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9202          * mouseout events for children elements
9203          * @return {Roo.Element} this
9204          */
9205         addClassOnOver : function(className, preventFlicker){
9206             this.on("mouseover", function(){
9207                 Roo.fly(this, '_internal').addClass(className);
9208             }, this.dom);
9209             var removeFn = function(e){
9210                 if(preventFlicker !== true || !e.within(this, true)){
9211                     Roo.fly(this, '_internal').removeClass(className);
9212                 }
9213             };
9214             this.on("mouseout", removeFn, this.dom);
9215             return this;
9216         },
9217
9218         /**
9219          * Sets up event handlers to add and remove a css class when this element has the focus
9220          * @param {String} className
9221          * @return {Roo.Element} this
9222          */
9223         addClassOnFocus : function(className){
9224             this.on("focus", function(){
9225                 Roo.fly(this, '_internal').addClass(className);
9226             }, this.dom);
9227             this.on("blur", function(){
9228                 Roo.fly(this, '_internal').removeClass(className);
9229             }, this.dom);
9230             return this;
9231         },
9232         /**
9233          * 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)
9234          * @param {String} className
9235          * @return {Roo.Element} this
9236          */
9237         addClassOnClick : function(className){
9238             var dom = this.dom;
9239             this.on("mousedown", function(){
9240                 Roo.fly(dom, '_internal').addClass(className);
9241                 var d = Roo.get(document);
9242                 var fn = function(){
9243                     Roo.fly(dom, '_internal').removeClass(className);
9244                     d.removeListener("mouseup", fn);
9245                 };
9246                 d.on("mouseup", fn);
9247             });
9248             return this;
9249         },
9250
9251         /**
9252          * Stops the specified event from bubbling and optionally prevents the default action
9253          * @param {String} eventName
9254          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9255          * @return {Roo.Element} this
9256          */
9257         swallowEvent : function(eventName, preventDefault){
9258             var fn = function(e){
9259                 e.stopPropagation();
9260                 if(preventDefault){
9261                     e.preventDefault();
9262                 }
9263             };
9264             if(eventName instanceof Array){
9265                 for(var i = 0, len = eventName.length; i < len; i++){
9266                      this.on(eventName[i], fn);
9267                 }
9268                 return this;
9269             }
9270             this.on(eventName, fn);
9271             return this;
9272         },
9273
9274         /**
9275          * @private
9276          */
9277       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9278
9279         /**
9280          * Sizes this element to its parent element's dimensions performing
9281          * neccessary box adjustments.
9282          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9283          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9284          * @return {Roo.Element} this
9285          */
9286         fitToParent : function(monitorResize, targetParent) {
9287           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9288           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9289           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9290             return;
9291           }
9292           var p = Roo.get(targetParent || this.dom.parentNode);
9293           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9294           if (monitorResize === true) {
9295             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9296             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9297           }
9298           return this;
9299         },
9300
9301         /**
9302          * Gets the next sibling, skipping text nodes
9303          * @return {HTMLElement} The next sibling or null
9304          */
9305         getNextSibling : function(){
9306             var n = this.dom.nextSibling;
9307             while(n && n.nodeType != 1){
9308                 n = n.nextSibling;
9309             }
9310             return n;
9311         },
9312
9313         /**
9314          * Gets the previous sibling, skipping text nodes
9315          * @return {HTMLElement} The previous sibling or null
9316          */
9317         getPrevSibling : function(){
9318             var n = this.dom.previousSibling;
9319             while(n && n.nodeType != 1){
9320                 n = n.previousSibling;
9321             }
9322             return n;
9323         },
9324
9325
9326         /**
9327          * Appends the passed element(s) to this element
9328          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9329          * @return {Roo.Element} this
9330          */
9331         appendChild: function(el){
9332             el = Roo.get(el);
9333             el.appendTo(this);
9334             return this;
9335         },
9336
9337         /**
9338          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9339          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9340          * automatically generated with the specified attributes.
9341          * @param {HTMLElement} insertBefore (optional) a child element of this element
9342          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9343          * @return {Roo.Element} The new child element
9344          */
9345         createChild: function(config, insertBefore, returnDom){
9346             config = config || {tag:'div'};
9347             if(insertBefore){
9348                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9349             }
9350             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9351         },
9352
9353         /**
9354          * Appends this element to the passed element
9355          * @param {String/HTMLElement/Element} el The new parent element
9356          * @return {Roo.Element} this
9357          */
9358         appendTo: function(el){
9359             el = Roo.getDom(el);
9360             el.appendChild(this.dom);
9361             return this;
9362         },
9363
9364         /**
9365          * Inserts this element before the passed element in the DOM
9366          * @param {String/HTMLElement/Element} el The element to insert before
9367          * @return {Roo.Element} this
9368          */
9369         insertBefore: function(el){
9370             el = Roo.getDom(el);
9371             el.parentNode.insertBefore(this.dom, el);
9372             return this;
9373         },
9374
9375         /**
9376          * Inserts this element after the passed element in the DOM
9377          * @param {String/HTMLElement/Element} el The element to insert after
9378          * @return {Roo.Element} this
9379          */
9380         insertAfter: function(el){
9381             el = Roo.getDom(el);
9382             el.parentNode.insertBefore(this.dom, el.nextSibling);
9383             return this;
9384         },
9385
9386         /**
9387          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9388          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9389          * @return {Roo.Element} The new child
9390          */
9391         insertFirst: function(el, returnDom){
9392             el = el || {};
9393             if(typeof el == 'object' && !el.nodeType){ // dh config
9394                 return this.createChild(el, this.dom.firstChild, returnDom);
9395             }else{
9396                 el = Roo.getDom(el);
9397                 this.dom.insertBefore(el, this.dom.firstChild);
9398                 return !returnDom ? Roo.get(el) : el;
9399             }
9400         },
9401
9402         /**
9403          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9404          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9405          * @param {String} where (optional) 'before' or 'after' defaults to before
9406          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9407          * @return {Roo.Element} the inserted Element
9408          */
9409         insertSibling: function(el, where, returnDom){
9410             where = where ? where.toLowerCase() : 'before';
9411             el = el || {};
9412             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9413
9414             if(typeof el == 'object' && !el.nodeType){ // dh config
9415                 if(where == 'after' && !this.dom.nextSibling){
9416                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9417                 }else{
9418                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9419                 }
9420
9421             }else{
9422                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9423                             where == 'before' ? this.dom : this.dom.nextSibling);
9424                 if(!returnDom){
9425                     rt = Roo.get(rt);
9426                 }
9427             }
9428             return rt;
9429         },
9430
9431         /**
9432          * Creates and wraps this element with another element
9433          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9434          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9435          * @return {HTMLElement/Element} The newly created wrapper element
9436          */
9437         wrap: function(config, returnDom){
9438             if(!config){
9439                 config = {tag: "div"};
9440             }
9441             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9442             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9443             return newEl;
9444         },
9445
9446         /**
9447          * Replaces the passed element with this element
9448          * @param {String/HTMLElement/Element} el The element to replace
9449          * @return {Roo.Element} this
9450          */
9451         replace: function(el){
9452             el = Roo.get(el);
9453             this.insertBefore(el);
9454             el.remove();
9455             return this;
9456         },
9457
9458         /**
9459          * Inserts an html fragment into this element
9460          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9461          * @param {String} html The HTML fragment
9462          * @param {Boolean} returnEl True to return an Roo.Element
9463          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9464          */
9465         insertHtml : function(where, html, returnEl){
9466             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9467             return returnEl ? Roo.get(el) : el;
9468         },
9469
9470         /**
9471          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9472          * @param {Object} o The object with the attributes
9473          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9474          * @return {Roo.Element} this
9475          */
9476         set : function(o, useSet){
9477             var el = this.dom;
9478             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9479             for(var attr in o){
9480                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9481                 if(attr=="cls"){
9482                     el.className = o["cls"];
9483                 }else{
9484                     if(useSet) {
9485                         el.setAttribute(attr, o[attr]);
9486                     } else {
9487                         el[attr] = o[attr];
9488                     }
9489                 }
9490             }
9491             if(o.style){
9492                 Roo.DomHelper.applyStyles(el, o.style);
9493             }
9494             return this;
9495         },
9496
9497         /**
9498          * Convenience method for constructing a KeyMap
9499          * @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:
9500          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9501          * @param {Function} fn The function to call
9502          * @param {Object} scope (optional) The scope of the function
9503          * @return {Roo.KeyMap} The KeyMap created
9504          */
9505         addKeyListener : function(key, fn, scope){
9506             var config;
9507             if(typeof key != "object" || key instanceof Array){
9508                 config = {
9509                     key: key,
9510                     fn: fn,
9511                     scope: scope
9512                 };
9513             }else{
9514                 config = {
9515                     key : key.key,
9516                     shift : key.shift,
9517                     ctrl : key.ctrl,
9518                     alt : key.alt,
9519                     fn: fn,
9520                     scope: scope
9521                 };
9522             }
9523             return new Roo.KeyMap(this, config);
9524         },
9525
9526         /**
9527          * Creates a KeyMap for this element
9528          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9529          * @return {Roo.KeyMap} The KeyMap created
9530          */
9531         addKeyMap : function(config){
9532             return new Roo.KeyMap(this, config);
9533         },
9534
9535         /**
9536          * Returns true if this element is scrollable.
9537          * @return {Boolean}
9538          */
9539          isScrollable : function(){
9540             var dom = this.dom;
9541             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9542         },
9543
9544         /**
9545          * 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().
9546          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9547          * @param {Number} value The new scroll value
9548          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9549          * @return {Element} this
9550          */
9551
9552         scrollTo : function(side, value, animate){
9553             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9554             if(!animate || !A){
9555                 this.dom[prop] = value;
9556             }else{
9557                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9558                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9559             }
9560             return this;
9561         },
9562
9563         /**
9564          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9565          * within this element's scrollable range.
9566          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9567          * @param {Number} distance How far to scroll the element in pixels
9568          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9569          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9570          * was scrolled as far as it could go.
9571          */
9572          scroll : function(direction, distance, animate){
9573              if(!this.isScrollable()){
9574                  return;
9575              }
9576              var el = this.dom;
9577              var l = el.scrollLeft, t = el.scrollTop;
9578              var w = el.scrollWidth, h = el.scrollHeight;
9579              var cw = el.clientWidth, ch = el.clientHeight;
9580              direction = direction.toLowerCase();
9581              var scrolled = false;
9582              var a = this.preanim(arguments, 2);
9583              switch(direction){
9584                  case "l":
9585                  case "left":
9586                      if(w - l > cw){
9587                          var v = Math.min(l + distance, w-cw);
9588                          this.scrollTo("left", v, a);
9589                          scrolled = true;
9590                      }
9591                      break;
9592                 case "r":
9593                 case "right":
9594                      if(l > 0){
9595                          var v = Math.max(l - distance, 0);
9596                          this.scrollTo("left", v, a);
9597                          scrolled = true;
9598                      }
9599                      break;
9600                 case "t":
9601                 case "top":
9602                 case "up":
9603                      if(t > 0){
9604                          var v = Math.max(t - distance, 0);
9605                          this.scrollTo("top", v, a);
9606                          scrolled = true;
9607                      }
9608                      break;
9609                 case "b":
9610                 case "bottom":
9611                 case "down":
9612                      if(h - t > ch){
9613                          var v = Math.min(t + distance, h-ch);
9614                          this.scrollTo("top", v, a);
9615                          scrolled = true;
9616                      }
9617                      break;
9618              }
9619              return scrolled;
9620         },
9621
9622         /**
9623          * Translates the passed page coordinates into left/top css values for this element
9624          * @param {Number/Array} x The page x or an array containing [x, y]
9625          * @param {Number} y The page y
9626          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9627          */
9628         translatePoints : function(x, y){
9629             if(typeof x == 'object' || x instanceof Array){
9630                 y = x[1]; x = x[0];
9631             }
9632             var p = this.getStyle('position');
9633             var o = this.getXY();
9634
9635             var l = parseInt(this.getStyle('left'), 10);
9636             var t = parseInt(this.getStyle('top'), 10);
9637
9638             if(isNaN(l)){
9639                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9640             }
9641             if(isNaN(t)){
9642                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9643             }
9644
9645             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9646         },
9647
9648         /**
9649          * Returns the current scroll position of the element.
9650          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9651          */
9652         getScroll : function(){
9653             var d = this.dom, doc = document;
9654             if(d == doc || d == doc.body){
9655                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9656                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9657                 return {left: l, top: t};
9658             }else{
9659                 return {left: d.scrollLeft, top: d.scrollTop};
9660             }
9661         },
9662
9663         /**
9664          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9665          * are convert to standard 6 digit hex color.
9666          * @param {String} attr The css attribute
9667          * @param {String} defaultValue The default value to use when a valid color isn't found
9668          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9669          * YUI color anims.
9670          */
9671         getColor : function(attr, defaultValue, prefix){
9672             var v = this.getStyle(attr);
9673             if(!v || v == "transparent" || v == "inherit") {
9674                 return defaultValue;
9675             }
9676             var color = typeof prefix == "undefined" ? "#" : prefix;
9677             if(v.substr(0, 4) == "rgb("){
9678                 var rvs = v.slice(4, v.length -1).split(",");
9679                 for(var i = 0; i < 3; i++){
9680                     var h = parseInt(rvs[i]).toString(16);
9681                     if(h < 16){
9682                         h = "0" + h;
9683                     }
9684                     color += h;
9685                 }
9686             } else {
9687                 if(v.substr(0, 1) == "#"){
9688                     if(v.length == 4) {
9689                         for(var i = 1; i < 4; i++){
9690                             var c = v.charAt(i);
9691                             color +=  c + c;
9692                         }
9693                     }else if(v.length == 7){
9694                         color += v.substr(1);
9695                     }
9696                 }
9697             }
9698             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9699         },
9700
9701         /**
9702          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9703          * gradient background, rounded corners and a 4-way shadow.
9704          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9705          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9706          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9707          * @return {Roo.Element} this
9708          */
9709         boxWrap : function(cls){
9710             cls = cls || 'x-box';
9711             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9712             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9713             return el;
9714         },
9715
9716         /**
9717          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9718          * @param {String} namespace The namespace in which to look for the attribute
9719          * @param {String} name The attribute name
9720          * @return {String} The attribute value
9721          */
9722         getAttributeNS : Roo.isIE ? function(ns, name){
9723             var d = this.dom;
9724             var type = typeof d[ns+":"+name];
9725             if(type != 'undefined' && type != 'unknown'){
9726                 return d[ns+":"+name];
9727             }
9728             return d[name];
9729         } : function(ns, name){
9730             var d = this.dom;
9731             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9732         },
9733         
9734         
9735         /**
9736          * Sets or Returns the value the dom attribute value
9737          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9738          * @param {String} value (optional) The value to set the attribute to
9739          * @return {String} The attribute value
9740          */
9741         attr : function(name){
9742             if (arguments.length > 1) {
9743                 this.dom.setAttribute(name, arguments[1]);
9744                 return arguments[1];
9745             }
9746             if (typeof(name) == 'object') {
9747                 for(var i in name) {
9748                     this.attr(i, name[i]);
9749                 }
9750                 return name;
9751             }
9752             
9753             
9754             if (!this.dom.hasAttribute(name)) {
9755                 return undefined;
9756             }
9757             return this.dom.getAttribute(name);
9758         }
9759         
9760         
9761         
9762     };
9763
9764     var ep = El.prototype;
9765
9766     /**
9767      * Appends an event handler (Shorthand for addListener)
9768      * @param {String}   eventName     The type of event to append
9769      * @param {Function} fn        The method the event invokes
9770      * @param {Object} scope       (optional) The scope (this object) of the fn
9771      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9772      * @method
9773      */
9774     ep.on = ep.addListener;
9775         // backwards compat
9776     ep.mon = ep.addListener;
9777
9778     /**
9779      * Removes an event handler from this element (shorthand for removeListener)
9780      * @param {String} eventName the type of event to remove
9781      * @param {Function} fn the method the event invokes
9782      * @return {Roo.Element} this
9783      * @method
9784      */
9785     ep.un = ep.removeListener;
9786
9787     /**
9788      * true to automatically adjust width and height settings for box-model issues (default to true)
9789      */
9790     ep.autoBoxAdjust = true;
9791
9792     // private
9793     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9794
9795     // private
9796     El.addUnits = function(v, defaultUnit){
9797         if(v === "" || v == "auto"){
9798             return v;
9799         }
9800         if(v === undefined){
9801             return '';
9802         }
9803         if(typeof v == "number" || !El.unitPattern.test(v)){
9804             return v + (defaultUnit || 'px');
9805         }
9806         return v;
9807     };
9808
9809     // special markup used throughout Roo when box wrapping elements
9810     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>';
9811     /**
9812      * Visibility mode constant - Use visibility to hide element
9813      * @static
9814      * @type Number
9815      */
9816     El.VISIBILITY = 1;
9817     /**
9818      * Visibility mode constant - Use display to hide element
9819      * @static
9820      * @type Number
9821      */
9822     El.DISPLAY = 2;
9823
9824     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9825     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9826     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9827
9828
9829
9830     /**
9831      * @private
9832      */
9833     El.cache = {};
9834
9835     var docEl;
9836
9837     /**
9838      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9839      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9840      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9841      * @return {Element} The Element object
9842      * @static
9843      */
9844     El.get = function(el){
9845         var ex, elm, id;
9846         if(!el){ return null; }
9847         if(typeof el == "string"){ // element id
9848             if(!(elm = document.getElementById(el))){
9849                 return null;
9850             }
9851             if(ex = El.cache[el]){
9852                 ex.dom = elm;
9853             }else{
9854                 ex = El.cache[el] = new El(elm);
9855             }
9856             return ex;
9857         }else if(el.tagName){ // dom element
9858             if(!(id = el.id)){
9859                 id = Roo.id(el);
9860             }
9861             if(ex = El.cache[id]){
9862                 ex.dom = el;
9863             }else{
9864                 ex = El.cache[id] = new El(el);
9865             }
9866             return ex;
9867         }else if(el instanceof El){
9868             if(el != docEl){
9869                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9870                                                               // catch case where it hasn't been appended
9871                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9872             }
9873             return el;
9874         }else if(el.isComposite){
9875             return el;
9876         }else if(el instanceof Array){
9877             return El.select(el);
9878         }else if(el == document){
9879             // create a bogus element object representing the document object
9880             if(!docEl){
9881                 var f = function(){};
9882                 f.prototype = El.prototype;
9883                 docEl = new f();
9884                 docEl.dom = document;
9885             }
9886             return docEl;
9887         }
9888         return null;
9889     };
9890
9891     // private
9892     El.uncache = function(el){
9893         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9894             if(a[i]){
9895                 delete El.cache[a[i].id || a[i]];
9896             }
9897         }
9898     };
9899
9900     // private
9901     // Garbage collection - uncache elements/purge listeners on orphaned elements
9902     // so we don't hold a reference and cause the browser to retain them
9903     El.garbageCollect = function(){
9904         if(!Roo.enableGarbageCollector){
9905             clearInterval(El.collectorThread);
9906             return;
9907         }
9908         for(var eid in El.cache){
9909             var el = El.cache[eid], d = el.dom;
9910             // -------------------------------------------------------
9911             // Determining what is garbage:
9912             // -------------------------------------------------------
9913             // !d
9914             // dom node is null, definitely garbage
9915             // -------------------------------------------------------
9916             // !d.parentNode
9917             // no parentNode == direct orphan, definitely garbage
9918             // -------------------------------------------------------
9919             // !d.offsetParent && !document.getElementById(eid)
9920             // display none elements have no offsetParent so we will
9921             // also try to look it up by it's id. However, check
9922             // offsetParent first so we don't do unneeded lookups.
9923             // This enables collection of elements that are not orphans
9924             // directly, but somewhere up the line they have an orphan
9925             // parent.
9926             // -------------------------------------------------------
9927             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9928                 delete El.cache[eid];
9929                 if(d && Roo.enableListenerCollection){
9930                     E.purgeElement(d);
9931                 }
9932             }
9933         }
9934     }
9935     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9936
9937
9938     // dom is optional
9939     El.Flyweight = function(dom){
9940         this.dom = dom;
9941     };
9942     El.Flyweight.prototype = El.prototype;
9943
9944     El._flyweights = {};
9945     /**
9946      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9947      * the dom node can be overwritten by other code.
9948      * @param {String/HTMLElement} el The dom node or id
9949      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9950      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9951      * @static
9952      * @return {Element} The shared Element object
9953      */
9954     El.fly = function(el, named){
9955         named = named || '_global';
9956         el = Roo.getDom(el);
9957         if(!el){
9958             return null;
9959         }
9960         if(!El._flyweights[named]){
9961             El._flyweights[named] = new El.Flyweight();
9962         }
9963         El._flyweights[named].dom = el;
9964         return El._flyweights[named];
9965     };
9966
9967     /**
9968      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9969      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9970      * Shorthand of {@link Roo.Element#get}
9971      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9972      * @return {Element} The Element object
9973      * @member Roo
9974      * @method get
9975      */
9976     Roo.get = El.get;
9977     /**
9978      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9979      * the dom node can be overwritten by other code.
9980      * Shorthand of {@link Roo.Element#fly}
9981      * @param {String/HTMLElement} el The dom node or id
9982      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9983      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9984      * @static
9985      * @return {Element} The shared Element object
9986      * @member Roo
9987      * @method fly
9988      */
9989     Roo.fly = El.fly;
9990
9991     // speedy lookup for elements never to box adjust
9992     var noBoxAdjust = Roo.isStrict ? {
9993         select:1
9994     } : {
9995         input:1, select:1, textarea:1
9996     };
9997     if(Roo.isIE || Roo.isGecko){
9998         noBoxAdjust['button'] = 1;
9999     }
10000
10001
10002     Roo.EventManager.on(window, 'unload', function(){
10003         delete El.cache;
10004         delete El._flyweights;
10005     });
10006 })();
10007
10008
10009
10010
10011 if(Roo.DomQuery){
10012     Roo.Element.selectorFunction = Roo.DomQuery.select;
10013 }
10014
10015 Roo.Element.select = function(selector, unique, root){
10016     var els;
10017     if(typeof selector == "string"){
10018         els = Roo.Element.selectorFunction(selector, root);
10019     }else if(selector.length !== undefined){
10020         els = selector;
10021     }else{
10022         throw "Invalid selector";
10023     }
10024     if(unique === true){
10025         return new Roo.CompositeElement(els);
10026     }else{
10027         return new Roo.CompositeElementLite(els);
10028     }
10029 };
10030 /**
10031  * Selects elements based on the passed CSS selector to enable working on them as 1.
10032  * @param {String/Array} selector The CSS selector or an array of elements
10033  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10034  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10035  * @return {CompositeElementLite/CompositeElement}
10036  * @member Roo
10037  * @method select
10038  */
10039 Roo.select = Roo.Element.select;
10040
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054 /*
10055  * Based on:
10056  * Ext JS Library 1.1.1
10057  * Copyright(c) 2006-2007, Ext JS, LLC.
10058  *
10059  * Originally Released Under LGPL - original licence link has changed is not relivant.
10060  *
10061  * Fork - LGPL
10062  * <script type="text/javascript">
10063  */
10064
10065
10066
10067 //Notifies Element that fx methods are available
10068 Roo.enableFx = true;
10069
10070 /**
10071  * @class Roo.Fx
10072  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10073  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10074  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10075  * Element effects to work.</p><br/>
10076  *
10077  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10078  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10079  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10080  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10081  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10082  * expected results and should be done with care.</p><br/>
10083  *
10084  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10085  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10086 <pre>
10087 Value  Description
10088 -----  -----------------------------
10089 tl     The top left corner
10090 t      The center of the top edge
10091 tr     The top right corner
10092 l      The center of the left edge
10093 r      The center of the right edge
10094 bl     The bottom left corner
10095 b      The center of the bottom edge
10096 br     The bottom right corner
10097 </pre>
10098  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10099  * below are common options that can be passed to any Fx method.</b>
10100  * @cfg {Function} callback A function called when the effect is finished
10101  * @cfg {Object} scope The scope of the effect function
10102  * @cfg {String} easing A valid Easing value for the effect
10103  * @cfg {String} afterCls A css class to apply after the effect
10104  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10105  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10106  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10107  * effects that end with the element being visually hidden, ignored otherwise)
10108  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10109  * a function which returns such a specification that will be applied to the Element after the effect finishes
10110  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10111  * @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
10112  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10113  */
10114 Roo.Fx = {
10115         /**
10116          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10117          * origin for the slide effect.  This function automatically handles wrapping the element with
10118          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10119          * Usage:
10120          *<pre><code>
10121 // default: slide the element in from the top
10122 el.slideIn();
10123
10124 // custom: slide the element in from the right with a 2-second duration
10125 el.slideIn('r', { duration: 2 });
10126
10127 // common config options shown with default values
10128 el.slideIn('t', {
10129     easing: 'easeOut',
10130     duration: .5
10131 });
10132 </code></pre>
10133          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10134          * @param {Object} options (optional) Object literal with any of the Fx config options
10135          * @return {Roo.Element} The Element
10136          */
10137     slideIn : function(anchor, o){
10138         var el = this.getFxEl();
10139         o = o || {};
10140
10141         el.queueFx(o, function(){
10142
10143             anchor = anchor || "t";
10144
10145             // fix display to visibility
10146             this.fixDisplay();
10147
10148             // restore values after effect
10149             var r = this.getFxRestore();
10150             var b = this.getBox();
10151             // fixed size for slide
10152             this.setSize(b);
10153
10154             // wrap if needed
10155             var wrap = this.fxWrap(r.pos, o, "hidden");
10156
10157             var st = this.dom.style;
10158             st.visibility = "visible";
10159             st.position = "absolute";
10160
10161             // clear out temp styles after slide and unwrap
10162             var after = function(){
10163                 el.fxUnwrap(wrap, r.pos, o);
10164                 st.width = r.width;
10165                 st.height = r.height;
10166                 el.afterFx(o);
10167             };
10168             // time to calc the positions
10169             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10170
10171             switch(anchor.toLowerCase()){
10172                 case "t":
10173                     wrap.setSize(b.width, 0);
10174                     st.left = st.bottom = "0";
10175                     a = {height: bh};
10176                 break;
10177                 case "l":
10178                     wrap.setSize(0, b.height);
10179                     st.right = st.top = "0";
10180                     a = {width: bw};
10181                 break;
10182                 case "r":
10183                     wrap.setSize(0, b.height);
10184                     wrap.setX(b.right);
10185                     st.left = st.top = "0";
10186                     a = {width: bw, points: pt};
10187                 break;
10188                 case "b":
10189                     wrap.setSize(b.width, 0);
10190                     wrap.setY(b.bottom);
10191                     st.left = st.top = "0";
10192                     a = {height: bh, points: pt};
10193                 break;
10194                 case "tl":
10195                     wrap.setSize(0, 0);
10196                     st.right = st.bottom = "0";
10197                     a = {width: bw, height: bh};
10198                 break;
10199                 case "bl":
10200                     wrap.setSize(0, 0);
10201                     wrap.setY(b.y+b.height);
10202                     st.right = st.top = "0";
10203                     a = {width: bw, height: bh, points: pt};
10204                 break;
10205                 case "br":
10206                     wrap.setSize(0, 0);
10207                     wrap.setXY([b.right, b.bottom]);
10208                     st.left = st.top = "0";
10209                     a = {width: bw, height: bh, points: pt};
10210                 break;
10211                 case "tr":
10212                     wrap.setSize(0, 0);
10213                     wrap.setX(b.x+b.width);
10214                     st.left = st.bottom = "0";
10215                     a = {width: bw, height: bh, points: pt};
10216                 break;
10217             }
10218             this.dom.style.visibility = "visible";
10219             wrap.show();
10220
10221             arguments.callee.anim = wrap.fxanim(a,
10222                 o,
10223                 'motion',
10224                 .5,
10225                 'easeOut', after);
10226         });
10227         return this;
10228     },
10229     
10230         /**
10231          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10232          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10233          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10234          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10235          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10236          * Usage:
10237          *<pre><code>
10238 // default: slide the element out to the top
10239 el.slideOut();
10240
10241 // custom: slide the element out to the right with a 2-second duration
10242 el.slideOut('r', { duration: 2 });
10243
10244 // common config options shown with default values
10245 el.slideOut('t', {
10246     easing: 'easeOut',
10247     duration: .5,
10248     remove: false,
10249     useDisplay: false
10250 });
10251 </code></pre>
10252          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10253          * @param {Object} options (optional) Object literal with any of the Fx config options
10254          * @return {Roo.Element} The Element
10255          */
10256     slideOut : function(anchor, o){
10257         var el = this.getFxEl();
10258         o = o || {};
10259
10260         el.queueFx(o, function(){
10261
10262             anchor = anchor || "t";
10263
10264             // restore values after effect
10265             var r = this.getFxRestore();
10266             
10267             var b = this.getBox();
10268             // fixed size for slide
10269             this.setSize(b);
10270
10271             // wrap if needed
10272             var wrap = this.fxWrap(r.pos, o, "visible");
10273
10274             var st = this.dom.style;
10275             st.visibility = "visible";
10276             st.position = "absolute";
10277
10278             wrap.setSize(b);
10279
10280             var after = function(){
10281                 if(o.useDisplay){
10282                     el.setDisplayed(false);
10283                 }else{
10284                     el.hide();
10285                 }
10286
10287                 el.fxUnwrap(wrap, r.pos, o);
10288
10289                 st.width = r.width;
10290                 st.height = r.height;
10291
10292                 el.afterFx(o);
10293             };
10294
10295             var a, zero = {to: 0};
10296             switch(anchor.toLowerCase()){
10297                 case "t":
10298                     st.left = st.bottom = "0";
10299                     a = {height: zero};
10300                 break;
10301                 case "l":
10302                     st.right = st.top = "0";
10303                     a = {width: zero};
10304                 break;
10305                 case "r":
10306                     st.left = st.top = "0";
10307                     a = {width: zero, points: {to:[b.right, b.y]}};
10308                 break;
10309                 case "b":
10310                     st.left = st.top = "0";
10311                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10312                 break;
10313                 case "tl":
10314                     st.right = st.bottom = "0";
10315                     a = {width: zero, height: zero};
10316                 break;
10317                 case "bl":
10318                     st.right = st.top = "0";
10319                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10320                 break;
10321                 case "br":
10322                     st.left = st.top = "0";
10323                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10324                 break;
10325                 case "tr":
10326                     st.left = st.bottom = "0";
10327                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10328                 break;
10329             }
10330
10331             arguments.callee.anim = wrap.fxanim(a,
10332                 o,
10333                 'motion',
10334                 .5,
10335                 "easeOut", after);
10336         });
10337         return this;
10338     },
10339
10340         /**
10341          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10342          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10343          * The element must be removed from the DOM using the 'remove' config option if desired.
10344          * Usage:
10345          *<pre><code>
10346 // default
10347 el.puff();
10348
10349 // common config options shown with default values
10350 el.puff({
10351     easing: 'easeOut',
10352     duration: .5,
10353     remove: false,
10354     useDisplay: false
10355 });
10356 </code></pre>
10357          * @param {Object} options (optional) Object literal with any of the Fx config options
10358          * @return {Roo.Element} The Element
10359          */
10360     puff : function(o){
10361         var el = this.getFxEl();
10362         o = o || {};
10363
10364         el.queueFx(o, function(){
10365             this.clearOpacity();
10366             this.show();
10367
10368             // restore values after effect
10369             var r = this.getFxRestore();
10370             var st = this.dom.style;
10371
10372             var after = function(){
10373                 if(o.useDisplay){
10374                     el.setDisplayed(false);
10375                 }else{
10376                     el.hide();
10377                 }
10378
10379                 el.clearOpacity();
10380
10381                 el.setPositioning(r.pos);
10382                 st.width = r.width;
10383                 st.height = r.height;
10384                 st.fontSize = '';
10385                 el.afterFx(o);
10386             };
10387
10388             var width = this.getWidth();
10389             var height = this.getHeight();
10390
10391             arguments.callee.anim = this.fxanim({
10392                     width : {to: this.adjustWidth(width * 2)},
10393                     height : {to: this.adjustHeight(height * 2)},
10394                     points : {by: [-(width * .5), -(height * .5)]},
10395                     opacity : {to: 0},
10396                     fontSize: {to:200, unit: "%"}
10397                 },
10398                 o,
10399                 'motion',
10400                 .5,
10401                 "easeOut", after);
10402         });
10403         return this;
10404     },
10405
10406         /**
10407          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10408          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10409          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10410          * Usage:
10411          *<pre><code>
10412 // default
10413 el.switchOff();
10414
10415 // all config options shown with default values
10416 el.switchOff({
10417     easing: 'easeIn',
10418     duration: .3,
10419     remove: false,
10420     useDisplay: false
10421 });
10422 </code></pre>
10423          * @param {Object} options (optional) Object literal with any of the Fx config options
10424          * @return {Roo.Element} The Element
10425          */
10426     switchOff : function(o){
10427         var el = this.getFxEl();
10428         o = o || {};
10429
10430         el.queueFx(o, function(){
10431             this.clearOpacity();
10432             this.clip();
10433
10434             // restore values after effect
10435             var r = this.getFxRestore();
10436             var st = this.dom.style;
10437
10438             var after = function(){
10439                 if(o.useDisplay){
10440                     el.setDisplayed(false);
10441                 }else{
10442                     el.hide();
10443                 }
10444
10445                 el.clearOpacity();
10446                 el.setPositioning(r.pos);
10447                 st.width = r.width;
10448                 st.height = r.height;
10449
10450                 el.afterFx(o);
10451             };
10452
10453             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10454                 this.clearOpacity();
10455                 (function(){
10456                     this.fxanim({
10457                         height:{to:1},
10458                         points:{by:[0, this.getHeight() * .5]}
10459                     }, o, 'motion', 0.3, 'easeIn', after);
10460                 }).defer(100, this);
10461             });
10462         });
10463         return this;
10464     },
10465
10466     /**
10467      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10468      * changed using the "attr" config option) and then fading back to the original color. If no original
10469      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10470      * Usage:
10471 <pre><code>
10472 // default: highlight background to yellow
10473 el.highlight();
10474
10475 // custom: highlight foreground text to blue for 2 seconds
10476 el.highlight("0000ff", { attr: 'color', duration: 2 });
10477
10478 // common config options shown with default values
10479 el.highlight("ffff9c", {
10480     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10481     endColor: (current color) or "ffffff",
10482     easing: 'easeIn',
10483     duration: 1
10484 });
10485 </code></pre>
10486      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10487      * @param {Object} options (optional) Object literal with any of the Fx config options
10488      * @return {Roo.Element} The Element
10489      */ 
10490     highlight : function(color, o){
10491         var el = this.getFxEl();
10492         o = o || {};
10493
10494         el.queueFx(o, function(){
10495             color = color || "ffff9c";
10496             attr = o.attr || "backgroundColor";
10497
10498             this.clearOpacity();
10499             this.show();
10500
10501             var origColor = this.getColor(attr);
10502             var restoreColor = this.dom.style[attr];
10503             endColor = (o.endColor || origColor) || "ffffff";
10504
10505             var after = function(){
10506                 el.dom.style[attr] = restoreColor;
10507                 el.afterFx(o);
10508             };
10509
10510             var a = {};
10511             a[attr] = {from: color, to: endColor};
10512             arguments.callee.anim = this.fxanim(a,
10513                 o,
10514                 'color',
10515                 1,
10516                 'easeIn', after);
10517         });
10518         return this;
10519     },
10520
10521    /**
10522     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10523     * Usage:
10524 <pre><code>
10525 // default: a single light blue ripple
10526 el.frame();
10527
10528 // custom: 3 red ripples lasting 3 seconds total
10529 el.frame("ff0000", 3, { duration: 3 });
10530
10531 // common config options shown with default values
10532 el.frame("C3DAF9", 1, {
10533     duration: 1 //duration of entire animation (not each individual ripple)
10534     // Note: Easing is not configurable and will be ignored if included
10535 });
10536 </code></pre>
10537     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10538     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10539     * @param {Object} options (optional) Object literal with any of the Fx config options
10540     * @return {Roo.Element} The Element
10541     */
10542     frame : function(color, count, o){
10543         var el = this.getFxEl();
10544         o = o || {};
10545
10546         el.queueFx(o, function(){
10547             color = color || "#C3DAF9";
10548             if(color.length == 6){
10549                 color = "#" + color;
10550             }
10551             count = count || 1;
10552             duration = o.duration || 1;
10553             this.show();
10554
10555             var b = this.getBox();
10556             var animFn = function(){
10557                 var proxy = this.createProxy({
10558
10559                      style:{
10560                         visbility:"hidden",
10561                         position:"absolute",
10562                         "z-index":"35000", // yee haw
10563                         border:"0px solid " + color
10564                      }
10565                   });
10566                 var scale = Roo.isBorderBox ? 2 : 1;
10567                 proxy.animate({
10568                     top:{from:b.y, to:b.y - 20},
10569                     left:{from:b.x, to:b.x - 20},
10570                     borderWidth:{from:0, to:10},
10571                     opacity:{from:1, to:0},
10572                     height:{from:b.height, to:(b.height + (20*scale))},
10573                     width:{from:b.width, to:(b.width + (20*scale))}
10574                 }, duration, function(){
10575                     proxy.remove();
10576                 });
10577                 if(--count > 0){
10578                      animFn.defer((duration/2)*1000, this);
10579                 }else{
10580                     el.afterFx(o);
10581                 }
10582             };
10583             animFn.call(this);
10584         });
10585         return this;
10586     },
10587
10588    /**
10589     * Creates a pause before any subsequent queued effects begin.  If there are
10590     * no effects queued after the pause it will have no effect.
10591     * Usage:
10592 <pre><code>
10593 el.pause(1);
10594 </code></pre>
10595     * @param {Number} seconds The length of time to pause (in seconds)
10596     * @return {Roo.Element} The Element
10597     */
10598     pause : function(seconds){
10599         var el = this.getFxEl();
10600         var o = {};
10601
10602         el.queueFx(o, function(){
10603             setTimeout(function(){
10604                 el.afterFx(o);
10605             }, seconds * 1000);
10606         });
10607         return this;
10608     },
10609
10610    /**
10611     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10612     * using the "endOpacity" config option.
10613     * Usage:
10614 <pre><code>
10615 // default: fade in from opacity 0 to 100%
10616 el.fadeIn();
10617
10618 // custom: fade in from opacity 0 to 75% over 2 seconds
10619 el.fadeIn({ endOpacity: .75, duration: 2});
10620
10621 // common config options shown with default values
10622 el.fadeIn({
10623     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10624     easing: 'easeOut',
10625     duration: .5
10626 });
10627 </code></pre>
10628     * @param {Object} options (optional) Object literal with any of the Fx config options
10629     * @return {Roo.Element} The Element
10630     */
10631     fadeIn : function(o){
10632         var el = this.getFxEl();
10633         o = o || {};
10634         el.queueFx(o, function(){
10635             this.setOpacity(0);
10636             this.fixDisplay();
10637             this.dom.style.visibility = 'visible';
10638             var to = o.endOpacity || 1;
10639             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10640                 o, null, .5, "easeOut", function(){
10641                 if(to == 1){
10642                     this.clearOpacity();
10643                 }
10644                 el.afterFx(o);
10645             });
10646         });
10647         return this;
10648     },
10649
10650    /**
10651     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10652     * using the "endOpacity" config option.
10653     * Usage:
10654 <pre><code>
10655 // default: fade out from the element's current opacity to 0
10656 el.fadeOut();
10657
10658 // custom: fade out from the element's current opacity to 25% over 2 seconds
10659 el.fadeOut({ endOpacity: .25, duration: 2});
10660
10661 // common config options shown with default values
10662 el.fadeOut({
10663     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10664     easing: 'easeOut',
10665     duration: .5
10666     remove: false,
10667     useDisplay: false
10668 });
10669 </code></pre>
10670     * @param {Object} options (optional) Object literal with any of the Fx config options
10671     * @return {Roo.Element} The Element
10672     */
10673     fadeOut : function(o){
10674         var el = this.getFxEl();
10675         o = o || {};
10676         el.queueFx(o, function(){
10677             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10678                 o, null, .5, "easeOut", function(){
10679                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10680                      this.dom.style.display = "none";
10681                 }else{
10682                      this.dom.style.visibility = "hidden";
10683                 }
10684                 this.clearOpacity();
10685                 el.afterFx(o);
10686             });
10687         });
10688         return this;
10689     },
10690
10691    /**
10692     * Animates the transition of an element's dimensions from a starting height/width
10693     * to an ending height/width.
10694     * Usage:
10695 <pre><code>
10696 // change height and width to 100x100 pixels
10697 el.scale(100, 100);
10698
10699 // common config options shown with default values.  The height and width will default to
10700 // the element's existing values if passed as null.
10701 el.scale(
10702     [element's width],
10703     [element's height], {
10704     easing: 'easeOut',
10705     duration: .35
10706 });
10707 </code></pre>
10708     * @param {Number} width  The new width (pass undefined to keep the original width)
10709     * @param {Number} height  The new height (pass undefined to keep the original height)
10710     * @param {Object} options (optional) Object literal with any of the Fx config options
10711     * @return {Roo.Element} The Element
10712     */
10713     scale : function(w, h, o){
10714         this.shift(Roo.apply({}, o, {
10715             width: w,
10716             height: h
10717         }));
10718         return this;
10719     },
10720
10721    /**
10722     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10723     * Any of these properties not specified in the config object will not be changed.  This effect 
10724     * requires that at least one new dimension, position or opacity setting must be passed in on
10725     * the config object in order for the function to have any effect.
10726     * Usage:
10727 <pre><code>
10728 // slide the element horizontally to x position 200 while changing the height and opacity
10729 el.shift({ x: 200, height: 50, opacity: .8 });
10730
10731 // common config options shown with default values.
10732 el.shift({
10733     width: [element's width],
10734     height: [element's height],
10735     x: [element's x position],
10736     y: [element's y position],
10737     opacity: [element's opacity],
10738     easing: 'easeOut',
10739     duration: .35
10740 });
10741 </code></pre>
10742     * @param {Object} options  Object literal with any of the Fx config options
10743     * @return {Roo.Element} The Element
10744     */
10745     shift : function(o){
10746         var el = this.getFxEl();
10747         o = o || {};
10748         el.queueFx(o, function(){
10749             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10750             if(w !== undefined){
10751                 a.width = {to: this.adjustWidth(w)};
10752             }
10753             if(h !== undefined){
10754                 a.height = {to: this.adjustHeight(h)};
10755             }
10756             if(x !== undefined || y !== undefined){
10757                 a.points = {to: [
10758                     x !== undefined ? x : this.getX(),
10759                     y !== undefined ? y : this.getY()
10760                 ]};
10761             }
10762             if(op !== undefined){
10763                 a.opacity = {to: op};
10764             }
10765             if(o.xy !== undefined){
10766                 a.points = {to: o.xy};
10767             }
10768             arguments.callee.anim = this.fxanim(a,
10769                 o, 'motion', .35, "easeOut", function(){
10770                 el.afterFx(o);
10771             });
10772         });
10773         return this;
10774     },
10775
10776         /**
10777          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10778          * ending point of the effect.
10779          * Usage:
10780          *<pre><code>
10781 // default: slide the element downward while fading out
10782 el.ghost();
10783
10784 // custom: slide the element out to the right with a 2-second duration
10785 el.ghost('r', { duration: 2 });
10786
10787 // common config options shown with default values
10788 el.ghost('b', {
10789     easing: 'easeOut',
10790     duration: .5
10791     remove: false,
10792     useDisplay: false
10793 });
10794 </code></pre>
10795          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10796          * @param {Object} options (optional) Object literal with any of the Fx config options
10797          * @return {Roo.Element} The Element
10798          */
10799     ghost : function(anchor, o){
10800         var el = this.getFxEl();
10801         o = o || {};
10802
10803         el.queueFx(o, function(){
10804             anchor = anchor || "b";
10805
10806             // restore values after effect
10807             var r = this.getFxRestore();
10808             var w = this.getWidth(),
10809                 h = this.getHeight();
10810
10811             var st = this.dom.style;
10812
10813             var after = function(){
10814                 if(o.useDisplay){
10815                     el.setDisplayed(false);
10816                 }else{
10817                     el.hide();
10818                 }
10819
10820                 el.clearOpacity();
10821                 el.setPositioning(r.pos);
10822                 st.width = r.width;
10823                 st.height = r.height;
10824
10825                 el.afterFx(o);
10826             };
10827
10828             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10829             switch(anchor.toLowerCase()){
10830                 case "t":
10831                     pt.by = [0, -h];
10832                 break;
10833                 case "l":
10834                     pt.by = [-w, 0];
10835                 break;
10836                 case "r":
10837                     pt.by = [w, 0];
10838                 break;
10839                 case "b":
10840                     pt.by = [0, h];
10841                 break;
10842                 case "tl":
10843                     pt.by = [-w, -h];
10844                 break;
10845                 case "bl":
10846                     pt.by = [-w, h];
10847                 break;
10848                 case "br":
10849                     pt.by = [w, h];
10850                 break;
10851                 case "tr":
10852                     pt.by = [w, -h];
10853                 break;
10854             }
10855
10856             arguments.callee.anim = this.fxanim(a,
10857                 o,
10858                 'motion',
10859                 .5,
10860                 "easeOut", after);
10861         });
10862         return this;
10863     },
10864
10865         /**
10866          * Ensures that all effects queued after syncFx is called on the element are
10867          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10868          * @return {Roo.Element} The Element
10869          */
10870     syncFx : function(){
10871         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10872             block : false,
10873             concurrent : true,
10874             stopFx : false
10875         });
10876         return this;
10877     },
10878
10879         /**
10880          * Ensures that all effects queued after sequenceFx is called on the element are
10881          * run in sequence.  This is the opposite of {@link #syncFx}.
10882          * @return {Roo.Element} The Element
10883          */
10884     sequenceFx : function(){
10885         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10886             block : false,
10887             concurrent : false,
10888             stopFx : false
10889         });
10890         return this;
10891     },
10892
10893         /* @private */
10894     nextFx : function(){
10895         var ef = this.fxQueue[0];
10896         if(ef){
10897             ef.call(this);
10898         }
10899     },
10900
10901         /**
10902          * Returns true if the element has any effects actively running or queued, else returns false.
10903          * @return {Boolean} True if element has active effects, else false
10904          */
10905     hasActiveFx : function(){
10906         return this.fxQueue && this.fxQueue[0];
10907     },
10908
10909         /**
10910          * Stops any running effects and clears the element's internal effects queue if it contains
10911          * any additional effects that haven't started yet.
10912          * @return {Roo.Element} The Element
10913          */
10914     stopFx : function(){
10915         if(this.hasActiveFx()){
10916             var cur = this.fxQueue[0];
10917             if(cur && cur.anim && cur.anim.isAnimated()){
10918                 this.fxQueue = [cur]; // clear out others
10919                 cur.anim.stop(true);
10920             }
10921         }
10922         return this;
10923     },
10924
10925         /* @private */
10926     beforeFx : function(o){
10927         if(this.hasActiveFx() && !o.concurrent){
10928            if(o.stopFx){
10929                this.stopFx();
10930                return true;
10931            }
10932            return false;
10933         }
10934         return true;
10935     },
10936
10937         /**
10938          * Returns true if the element is currently blocking so that no other effect can be queued
10939          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10940          * used to ensure that an effect initiated by a user action runs to completion prior to the
10941          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10942          * @return {Boolean} True if blocking, else false
10943          */
10944     hasFxBlock : function(){
10945         var q = this.fxQueue;
10946         return q && q[0] && q[0].block;
10947     },
10948
10949         /* @private */
10950     queueFx : function(o, fn){
10951         if(!this.fxQueue){
10952             this.fxQueue = [];
10953         }
10954         if(!this.hasFxBlock()){
10955             Roo.applyIf(o, this.fxDefaults);
10956             if(!o.concurrent){
10957                 var run = this.beforeFx(o);
10958                 fn.block = o.block;
10959                 this.fxQueue.push(fn);
10960                 if(run){
10961                     this.nextFx();
10962                 }
10963             }else{
10964                 fn.call(this);
10965             }
10966         }
10967         return this;
10968     },
10969
10970         /* @private */
10971     fxWrap : function(pos, o, vis){
10972         var wrap;
10973         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10974             var wrapXY;
10975             if(o.fixPosition){
10976                 wrapXY = this.getXY();
10977             }
10978             var div = document.createElement("div");
10979             div.style.visibility = vis;
10980             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10981             wrap.setPositioning(pos);
10982             if(wrap.getStyle("position") == "static"){
10983                 wrap.position("relative");
10984             }
10985             this.clearPositioning('auto');
10986             wrap.clip();
10987             wrap.dom.appendChild(this.dom);
10988             if(wrapXY){
10989                 wrap.setXY(wrapXY);
10990             }
10991         }
10992         return wrap;
10993     },
10994
10995         /* @private */
10996     fxUnwrap : function(wrap, pos, o){
10997         this.clearPositioning();
10998         this.setPositioning(pos);
10999         if(!o.wrap){
11000             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11001             wrap.remove();
11002         }
11003     },
11004
11005         /* @private */
11006     getFxRestore : function(){
11007         var st = this.dom.style;
11008         return {pos: this.getPositioning(), width: st.width, height : st.height};
11009     },
11010
11011         /* @private */
11012     afterFx : function(o){
11013         if(o.afterStyle){
11014             this.applyStyles(o.afterStyle);
11015         }
11016         if(o.afterCls){
11017             this.addClass(o.afterCls);
11018         }
11019         if(o.remove === true){
11020             this.remove();
11021         }
11022         Roo.callback(o.callback, o.scope, [this]);
11023         if(!o.concurrent){
11024             this.fxQueue.shift();
11025             this.nextFx();
11026         }
11027     },
11028
11029         /* @private */
11030     getFxEl : function(){ // support for composite element fx
11031         return Roo.get(this.dom);
11032     },
11033
11034         /* @private */
11035     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11036         animType = animType || 'run';
11037         opt = opt || {};
11038         var anim = Roo.lib.Anim[animType](
11039             this.dom, args,
11040             (opt.duration || defaultDur) || .35,
11041             (opt.easing || defaultEase) || 'easeOut',
11042             function(){
11043                 Roo.callback(cb, this);
11044             },
11045             this
11046         );
11047         opt.anim = anim;
11048         return anim;
11049     }
11050 };
11051
11052 // backwords compat
11053 Roo.Fx.resize = Roo.Fx.scale;
11054
11055 //When included, Roo.Fx is automatically applied to Element so that all basic
11056 //effects are available directly via the Element API
11057 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11058  * Based on:
11059  * Ext JS Library 1.1.1
11060  * Copyright(c) 2006-2007, Ext JS, LLC.
11061  *
11062  * Originally Released Under LGPL - original licence link has changed is not relivant.
11063  *
11064  * Fork - LGPL
11065  * <script type="text/javascript">
11066  */
11067
11068
11069 /**
11070  * @class Roo.CompositeElement
11071  * Standard composite class. Creates a Roo.Element for every element in the collection.
11072  * <br><br>
11073  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11074  * actions will be performed on all the elements in this collection.</b>
11075  * <br><br>
11076  * All methods return <i>this</i> and can be chained.
11077  <pre><code>
11078  var els = Roo.select("#some-el div.some-class", true);
11079  // or select directly from an existing element
11080  var el = Roo.get('some-el');
11081  el.select('div.some-class', true);
11082
11083  els.setWidth(100); // all elements become 100 width
11084  els.hide(true); // all elements fade out and hide
11085  // or
11086  els.setWidth(100).hide(true);
11087  </code></pre>
11088  */
11089 Roo.CompositeElement = function(els){
11090     this.elements = [];
11091     this.addElements(els);
11092 };
11093 Roo.CompositeElement.prototype = {
11094     isComposite: true,
11095     addElements : function(els){
11096         if(!els) {
11097             return this;
11098         }
11099         if(typeof els == "string"){
11100             els = Roo.Element.selectorFunction(els);
11101         }
11102         var yels = this.elements;
11103         var index = yels.length-1;
11104         for(var i = 0, len = els.length; i < len; i++) {
11105                 yels[++index] = Roo.get(els[i]);
11106         }
11107         return this;
11108     },
11109
11110     /**
11111     * Clears this composite and adds the elements returned by the passed selector.
11112     * @param {String/Array} els A string CSS selector, an array of elements or an element
11113     * @return {CompositeElement} this
11114     */
11115     fill : function(els){
11116         this.elements = [];
11117         this.add(els);
11118         return this;
11119     },
11120
11121     /**
11122     * Filters this composite to only elements that match the passed selector.
11123     * @param {String} selector A string CSS selector
11124     * @param {Boolean} inverse return inverse filter (not matches)
11125     * @return {CompositeElement} this
11126     */
11127     filter : function(selector, inverse){
11128         var els = [];
11129         inverse = inverse || false;
11130         this.each(function(el){
11131             var match = inverse ? !el.is(selector) : el.is(selector);
11132             if(match){
11133                 els[els.length] = el.dom;
11134             }
11135         });
11136         this.fill(els);
11137         return this;
11138     },
11139
11140     invoke : function(fn, args){
11141         var els = this.elements;
11142         for(var i = 0, len = els.length; i < len; i++) {
11143                 Roo.Element.prototype[fn].apply(els[i], args);
11144         }
11145         return this;
11146     },
11147     /**
11148     * Adds elements to this composite.
11149     * @param {String/Array} els A string CSS selector, an array of elements or an element
11150     * @return {CompositeElement} this
11151     */
11152     add : function(els){
11153         if(typeof els == "string"){
11154             this.addElements(Roo.Element.selectorFunction(els));
11155         }else if(els.length !== undefined){
11156             this.addElements(els);
11157         }else{
11158             this.addElements([els]);
11159         }
11160         return this;
11161     },
11162     /**
11163     * Calls the passed function passing (el, this, index) for each element in this composite.
11164     * @param {Function} fn The function to call
11165     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11166     * @return {CompositeElement} this
11167     */
11168     each : function(fn, scope){
11169         var els = this.elements;
11170         for(var i = 0, len = els.length; i < len; i++){
11171             if(fn.call(scope || els[i], els[i], this, i) === false) {
11172                 break;
11173             }
11174         }
11175         return this;
11176     },
11177
11178     /**
11179      * Returns the Element object at the specified index
11180      * @param {Number} index
11181      * @return {Roo.Element}
11182      */
11183     item : function(index){
11184         return this.elements[index] || null;
11185     },
11186
11187     /**
11188      * Returns the first Element
11189      * @return {Roo.Element}
11190      */
11191     first : function(){
11192         return this.item(0);
11193     },
11194
11195     /**
11196      * Returns the last Element
11197      * @return {Roo.Element}
11198      */
11199     last : function(){
11200         return this.item(this.elements.length-1);
11201     },
11202
11203     /**
11204      * Returns the number of elements in this composite
11205      * @return Number
11206      */
11207     getCount : function(){
11208         return this.elements.length;
11209     },
11210
11211     /**
11212      * Returns true if this composite contains the passed element
11213      * @return Boolean
11214      */
11215     contains : function(el){
11216         return this.indexOf(el) !== -1;
11217     },
11218
11219     /**
11220      * Returns true if this composite contains the passed element
11221      * @return Boolean
11222      */
11223     indexOf : function(el){
11224         return this.elements.indexOf(Roo.get(el));
11225     },
11226
11227
11228     /**
11229     * Removes the specified element(s).
11230     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11231     * or an array of any of those.
11232     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11233     * @return {CompositeElement} this
11234     */
11235     removeElement : function(el, removeDom){
11236         if(el instanceof Array){
11237             for(var i = 0, len = el.length; i < len; i++){
11238                 this.removeElement(el[i]);
11239             }
11240             return this;
11241         }
11242         var index = typeof el == 'number' ? el : this.indexOf(el);
11243         if(index !== -1){
11244             if(removeDom){
11245                 var d = this.elements[index];
11246                 if(d.dom){
11247                     d.remove();
11248                 }else{
11249                     d.parentNode.removeChild(d);
11250                 }
11251             }
11252             this.elements.splice(index, 1);
11253         }
11254         return this;
11255     },
11256
11257     /**
11258     * Replaces the specified element with the passed element.
11259     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11260     * to replace.
11261     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11262     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11263     * @return {CompositeElement} this
11264     */
11265     replaceElement : function(el, replacement, domReplace){
11266         var index = typeof el == 'number' ? el : this.indexOf(el);
11267         if(index !== -1){
11268             if(domReplace){
11269                 this.elements[index].replaceWith(replacement);
11270             }else{
11271                 this.elements.splice(index, 1, Roo.get(replacement))
11272             }
11273         }
11274         return this;
11275     },
11276
11277     /**
11278      * Removes all elements.
11279      */
11280     clear : function(){
11281         this.elements = [];
11282     }
11283 };
11284 (function(){
11285     Roo.CompositeElement.createCall = function(proto, fnName){
11286         if(!proto[fnName]){
11287             proto[fnName] = function(){
11288                 return this.invoke(fnName, arguments);
11289             };
11290         }
11291     };
11292     for(var fnName in Roo.Element.prototype){
11293         if(typeof Roo.Element.prototype[fnName] == "function"){
11294             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11295         }
11296     };
11297 })();
11298 /*
11299  * Based on:
11300  * Ext JS Library 1.1.1
11301  * Copyright(c) 2006-2007, Ext JS, LLC.
11302  *
11303  * Originally Released Under LGPL - original licence link has changed is not relivant.
11304  *
11305  * Fork - LGPL
11306  * <script type="text/javascript">
11307  */
11308
11309 /**
11310  * @class Roo.CompositeElementLite
11311  * @extends Roo.CompositeElement
11312  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11313  <pre><code>
11314  var els = Roo.select("#some-el div.some-class");
11315  // or select directly from an existing element
11316  var el = Roo.get('some-el');
11317  el.select('div.some-class');
11318
11319  els.setWidth(100); // all elements become 100 width
11320  els.hide(true); // all elements fade out and hide
11321  // or
11322  els.setWidth(100).hide(true);
11323  </code></pre><br><br>
11324  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11325  * actions will be performed on all the elements in this collection.</b>
11326  */
11327 Roo.CompositeElementLite = function(els){
11328     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11329     this.el = new Roo.Element.Flyweight();
11330 };
11331 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11332     addElements : function(els){
11333         if(els){
11334             if(els instanceof Array){
11335                 this.elements = this.elements.concat(els);
11336             }else{
11337                 var yels = this.elements;
11338                 var index = yels.length-1;
11339                 for(var i = 0, len = els.length; i < len; i++) {
11340                     yels[++index] = els[i];
11341                 }
11342             }
11343         }
11344         return this;
11345     },
11346     invoke : function(fn, args){
11347         var els = this.elements;
11348         var el = this.el;
11349         for(var i = 0, len = els.length; i < len; i++) {
11350             el.dom = els[i];
11351                 Roo.Element.prototype[fn].apply(el, args);
11352         }
11353         return this;
11354     },
11355     /**
11356      * Returns a flyweight Element of the dom element object at the specified index
11357      * @param {Number} index
11358      * @return {Roo.Element}
11359      */
11360     item : function(index){
11361         if(!this.elements[index]){
11362             return null;
11363         }
11364         this.el.dom = this.elements[index];
11365         return this.el;
11366     },
11367
11368     // fixes scope with flyweight
11369     addListener : function(eventName, handler, scope, opt){
11370         var els = this.elements;
11371         for(var i = 0, len = els.length; i < len; i++) {
11372             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11373         }
11374         return this;
11375     },
11376
11377     /**
11378     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11379     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11380     * a reference to the dom node, use el.dom.</b>
11381     * @param {Function} fn The function to call
11382     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11383     * @return {CompositeElement} this
11384     */
11385     each : function(fn, scope){
11386         var els = this.elements;
11387         var el = this.el;
11388         for(var i = 0, len = els.length; i < len; i++){
11389             el.dom = els[i];
11390                 if(fn.call(scope || el, el, this, i) === false){
11391                 break;
11392             }
11393         }
11394         return this;
11395     },
11396
11397     indexOf : function(el){
11398         return this.elements.indexOf(Roo.getDom(el));
11399     },
11400
11401     replaceElement : function(el, replacement, domReplace){
11402         var index = typeof el == 'number' ? el : this.indexOf(el);
11403         if(index !== -1){
11404             replacement = Roo.getDom(replacement);
11405             if(domReplace){
11406                 var d = this.elements[index];
11407                 d.parentNode.insertBefore(replacement, d);
11408                 d.parentNode.removeChild(d);
11409             }
11410             this.elements.splice(index, 1, replacement);
11411         }
11412         return this;
11413     }
11414 });
11415 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11416
11417 /*
11418  * Based on:
11419  * Ext JS Library 1.1.1
11420  * Copyright(c) 2006-2007, Ext JS, LLC.
11421  *
11422  * Originally Released Under LGPL - original licence link has changed is not relivant.
11423  *
11424  * Fork - LGPL
11425  * <script type="text/javascript">
11426  */
11427
11428  
11429
11430 /**
11431  * @class Roo.data.Connection
11432  * @extends Roo.util.Observable
11433  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11434  * either to a configured URL, or to a URL specified at request time.<br><br>
11435  * <p>
11436  * Requests made by this class are asynchronous, and will return immediately. No data from
11437  * the server will be available to the statement immediately following the {@link #request} call.
11438  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11439  * <p>
11440  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11441  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11442  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11443  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11444  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11445  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11446  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11447  * standard DOM methods.
11448  * @constructor
11449  * @param {Object} config a configuration object.
11450  */
11451 Roo.data.Connection = function(config){
11452     Roo.apply(this, config);
11453     this.addEvents({
11454         /**
11455          * @event beforerequest
11456          * Fires before a network request is made to retrieve a data object.
11457          * @param {Connection} conn This Connection object.
11458          * @param {Object} options The options config object passed to the {@link #request} method.
11459          */
11460         "beforerequest" : true,
11461         /**
11462          * @event requestcomplete
11463          * Fires if the request was successfully completed.
11464          * @param {Connection} conn This Connection object.
11465          * @param {Object} response The XHR object containing the response data.
11466          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11467          * @param {Object} options The options config object passed to the {@link #request} method.
11468          */
11469         "requestcomplete" : true,
11470         /**
11471          * @event requestexception
11472          * Fires if an error HTTP status was returned from the server.
11473          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11474          * @param {Connection} conn This Connection object.
11475          * @param {Object} response The XHR object containing the response data.
11476          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11477          * @param {Object} options The options config object passed to the {@link #request} method.
11478          */
11479         "requestexception" : true
11480     });
11481     Roo.data.Connection.superclass.constructor.call(this);
11482 };
11483
11484 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11485     /**
11486      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11487      */
11488     /**
11489      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11490      * extra parameters to each request made by this object. (defaults to undefined)
11491      */
11492     /**
11493      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11494      *  to each request made by this object. (defaults to undefined)
11495      */
11496     /**
11497      * @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)
11498      */
11499     /**
11500      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11501      */
11502     timeout : 30000,
11503     /**
11504      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11505      * @type Boolean
11506      */
11507     autoAbort:false,
11508
11509     /**
11510      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11511      * @type Boolean
11512      */
11513     disableCaching: true,
11514
11515     /**
11516      * Sends an HTTP request to a remote server.
11517      * @param {Object} options An object which may contain the following properties:<ul>
11518      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11519      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11520      * request, a url encoded string or a function to call to get either.</li>
11521      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11522      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11523      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11524      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11525      * <li>options {Object} The parameter to the request call.</li>
11526      * <li>success {Boolean} True if the request succeeded.</li>
11527      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11528      * </ul></li>
11529      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11530      * The callback is passed the following parameters:<ul>
11531      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11532      * <li>options {Object} The parameter to the request call.</li>
11533      * </ul></li>
11534      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11535      * The callback is passed the following parameters:<ul>
11536      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11537      * <li>options {Object} The parameter to the request call.</li>
11538      * </ul></li>
11539      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11540      * for the callback function. Defaults to the browser window.</li>
11541      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11542      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11543      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11544      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11545      * params for the post data. Any params will be appended to the URL.</li>
11546      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11547      * </ul>
11548      * @return {Number} transactionId
11549      */
11550     request : function(o){
11551         if(this.fireEvent("beforerequest", this, o) !== false){
11552             var p = o.params;
11553
11554             if(typeof p == "function"){
11555                 p = p.call(o.scope||window, o);
11556             }
11557             if(typeof p == "object"){
11558                 p = Roo.urlEncode(o.params);
11559             }
11560             if(this.extraParams){
11561                 var extras = Roo.urlEncode(this.extraParams);
11562                 p = p ? (p + '&' + extras) : extras;
11563             }
11564
11565             var url = o.url || this.url;
11566             if(typeof url == 'function'){
11567                 url = url.call(o.scope||window, o);
11568             }
11569
11570             if(o.form){
11571                 var form = Roo.getDom(o.form);
11572                 url = url || form.action;
11573
11574                 var enctype = form.getAttribute("enctype");
11575                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11576                     return this.doFormUpload(o, p, url);
11577                 }
11578                 var f = Roo.lib.Ajax.serializeForm(form);
11579                 p = p ? (p + '&' + f) : f;
11580             }
11581
11582             var hs = o.headers;
11583             if(this.defaultHeaders){
11584                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11585                 if(!o.headers){
11586                     o.headers = hs;
11587                 }
11588             }
11589
11590             var cb = {
11591                 success: this.handleResponse,
11592                 failure: this.handleFailure,
11593                 scope: this,
11594                 argument: {options: o},
11595                 timeout : o.timeout || this.timeout
11596             };
11597
11598             var method = o.method||this.method||(p ? "POST" : "GET");
11599
11600             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11601                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11602             }
11603
11604             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11605                 if(o.autoAbort){
11606                     this.abort();
11607                 }
11608             }else if(this.autoAbort !== false){
11609                 this.abort();
11610             }
11611
11612             if((method == 'GET' && p) || o.xmlData){
11613                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11614                 p = '';
11615             }
11616             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11617             return this.transId;
11618         }else{
11619             Roo.callback(o.callback, o.scope, [o, null, null]);
11620             return null;
11621         }
11622     },
11623
11624     /**
11625      * Determine whether this object has a request outstanding.
11626      * @param {Number} transactionId (Optional) defaults to the last transaction
11627      * @return {Boolean} True if there is an outstanding request.
11628      */
11629     isLoading : function(transId){
11630         if(transId){
11631             return Roo.lib.Ajax.isCallInProgress(transId);
11632         }else{
11633             return this.transId ? true : false;
11634         }
11635     },
11636
11637     /**
11638      * Aborts any outstanding request.
11639      * @param {Number} transactionId (Optional) defaults to the last transaction
11640      */
11641     abort : function(transId){
11642         if(transId || this.isLoading()){
11643             Roo.lib.Ajax.abort(transId || this.transId);
11644         }
11645     },
11646
11647     // private
11648     handleResponse : function(response){
11649         this.transId = false;
11650         var options = response.argument.options;
11651         response.argument = options ? options.argument : null;
11652         this.fireEvent("requestcomplete", this, response, options);
11653         Roo.callback(options.success, options.scope, [response, options]);
11654         Roo.callback(options.callback, options.scope, [options, true, response]);
11655     },
11656
11657     // private
11658     handleFailure : function(response, e){
11659         this.transId = false;
11660         var options = response.argument.options;
11661         response.argument = options ? options.argument : null;
11662         this.fireEvent("requestexception", this, response, options, e);
11663         Roo.callback(options.failure, options.scope, [response, options]);
11664         Roo.callback(options.callback, options.scope, [options, false, response]);
11665     },
11666
11667     // private
11668     doFormUpload : function(o, ps, url){
11669         var id = Roo.id();
11670         var frame = document.createElement('iframe');
11671         frame.id = id;
11672         frame.name = id;
11673         frame.className = 'x-hidden';
11674         if(Roo.isIE){
11675             frame.src = Roo.SSL_SECURE_URL;
11676         }
11677         document.body.appendChild(frame);
11678
11679         if(Roo.isIE){
11680            document.frames[id].name = id;
11681         }
11682
11683         var form = Roo.getDom(o.form);
11684         form.target = id;
11685         form.method = 'POST';
11686         form.enctype = form.encoding = 'multipart/form-data';
11687         if(url){
11688             form.action = url;
11689         }
11690
11691         var hiddens, hd;
11692         if(ps){ // add dynamic params
11693             hiddens = [];
11694             ps = Roo.urlDecode(ps, false);
11695             for(var k in ps){
11696                 if(ps.hasOwnProperty(k)){
11697                     hd = document.createElement('input');
11698                     hd.type = 'hidden';
11699                     hd.name = k;
11700                     hd.value = ps[k];
11701                     form.appendChild(hd);
11702                     hiddens.push(hd);
11703                 }
11704             }
11705         }
11706
11707         function cb(){
11708             var r = {  // bogus response object
11709                 responseText : '',
11710                 responseXML : null
11711             };
11712
11713             r.argument = o ? o.argument : null;
11714
11715             try { //
11716                 var doc;
11717                 if(Roo.isIE){
11718                     doc = frame.contentWindow.document;
11719                 }else {
11720                     doc = (frame.contentDocument || window.frames[id].document);
11721                 }
11722                 if(doc && doc.body){
11723                     r.responseText = doc.body.innerHTML;
11724                 }
11725                 if(doc && doc.XMLDocument){
11726                     r.responseXML = doc.XMLDocument;
11727                 }else {
11728                     r.responseXML = doc;
11729                 }
11730             }
11731             catch(e) {
11732                 // ignore
11733             }
11734
11735             Roo.EventManager.removeListener(frame, 'load', cb, this);
11736
11737             this.fireEvent("requestcomplete", this, r, o);
11738             Roo.callback(o.success, o.scope, [r, o]);
11739             Roo.callback(o.callback, o.scope, [o, true, r]);
11740
11741             setTimeout(function(){document.body.removeChild(frame);}, 100);
11742         }
11743
11744         Roo.EventManager.on(frame, 'load', cb, this);
11745         form.submit();
11746
11747         if(hiddens){ // remove dynamic params
11748             for(var i = 0, len = hiddens.length; i < len; i++){
11749                 form.removeChild(hiddens[i]);
11750             }
11751         }
11752     }
11753 });
11754 /*
11755  * Based on:
11756  * Ext JS Library 1.1.1
11757  * Copyright(c) 2006-2007, Ext JS, LLC.
11758  *
11759  * Originally Released Under LGPL - original licence link has changed is not relivant.
11760  *
11761  * Fork - LGPL
11762  * <script type="text/javascript">
11763  */
11764  
11765 /**
11766  * Global Ajax request class.
11767  * 
11768  * @class Roo.Ajax
11769  * @extends Roo.data.Connection
11770  * @static
11771  * 
11772  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11773  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11774  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11775  * @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)
11776  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11777  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11778  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11779  */
11780 Roo.Ajax = new Roo.data.Connection({
11781     // fix up the docs
11782     /**
11783      * @scope Roo.Ajax
11784      * @type {Boolear} 
11785      */
11786     autoAbort : false,
11787
11788     /**
11789      * Serialize the passed form into a url encoded string
11790      * @scope Roo.Ajax
11791      * @param {String/HTMLElement} form
11792      * @return {String}
11793      */
11794     serializeForm : function(form){
11795         return Roo.lib.Ajax.serializeForm(form);
11796     }
11797 });/*
11798  * Based on:
11799  * Ext JS Library 1.1.1
11800  * Copyright(c) 2006-2007, Ext JS, LLC.
11801  *
11802  * Originally Released Under LGPL - original licence link has changed is not relivant.
11803  *
11804  * Fork - LGPL
11805  * <script type="text/javascript">
11806  */
11807
11808  
11809 /**
11810  * @class Roo.UpdateManager
11811  * @extends Roo.util.Observable
11812  * Provides AJAX-style update for Element object.<br><br>
11813  * Usage:<br>
11814  * <pre><code>
11815  * // Get it from a Roo.Element object
11816  * var el = Roo.get("foo");
11817  * var mgr = el.getUpdateManager();
11818  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11819  * ...
11820  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11821  * <br>
11822  * // or directly (returns the same UpdateManager instance)
11823  * var mgr = new Roo.UpdateManager("myElementId");
11824  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11825  * mgr.on("update", myFcnNeedsToKnow);
11826  * <br>
11827    // short handed call directly from the element object
11828    Roo.get("foo").load({
11829         url: "bar.php",
11830         scripts:true,
11831         params: "for=bar",
11832         text: "Loading Foo..."
11833    });
11834  * </code></pre>
11835  * @constructor
11836  * Create new UpdateManager directly.
11837  * @param {String/HTMLElement/Roo.Element} el The element to update
11838  * @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).
11839  */
11840 Roo.UpdateManager = function(el, forceNew){
11841     el = Roo.get(el);
11842     if(!forceNew && el.updateManager){
11843         return el.updateManager;
11844     }
11845     /**
11846      * The Element object
11847      * @type Roo.Element
11848      */
11849     this.el = el;
11850     /**
11851      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11852      * @type String
11853      */
11854     this.defaultUrl = null;
11855
11856     this.addEvents({
11857         /**
11858          * @event beforeupdate
11859          * Fired before an update is made, return false from your handler and the update is cancelled.
11860          * @param {Roo.Element} el
11861          * @param {String/Object/Function} url
11862          * @param {String/Object} params
11863          */
11864         "beforeupdate": true,
11865         /**
11866          * @event update
11867          * Fired after successful update is made.
11868          * @param {Roo.Element} el
11869          * @param {Object} oResponseObject The response Object
11870          */
11871         "update": true,
11872         /**
11873          * @event failure
11874          * Fired on update failure.
11875          * @param {Roo.Element} el
11876          * @param {Object} oResponseObject The response Object
11877          */
11878         "failure": true
11879     });
11880     var d = Roo.UpdateManager.defaults;
11881     /**
11882      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11883      * @type String
11884      */
11885     this.sslBlankUrl = d.sslBlankUrl;
11886     /**
11887      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11888      * @type Boolean
11889      */
11890     this.disableCaching = d.disableCaching;
11891     /**
11892      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11893      * @type String
11894      */
11895     this.indicatorText = d.indicatorText;
11896     /**
11897      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11898      * @type String
11899      */
11900     this.showLoadIndicator = d.showLoadIndicator;
11901     /**
11902      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11903      * @type Number
11904      */
11905     this.timeout = d.timeout;
11906
11907     /**
11908      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11909      * @type Boolean
11910      */
11911     this.loadScripts = d.loadScripts;
11912
11913     /**
11914      * Transaction object of current executing transaction
11915      */
11916     this.transaction = null;
11917
11918     /**
11919      * @private
11920      */
11921     this.autoRefreshProcId = null;
11922     /**
11923      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11924      * @type Function
11925      */
11926     this.refreshDelegate = this.refresh.createDelegate(this);
11927     /**
11928      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11929      * @type Function
11930      */
11931     this.updateDelegate = this.update.createDelegate(this);
11932     /**
11933      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11934      * @type Function
11935      */
11936     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11937     /**
11938      * @private
11939      */
11940     this.successDelegate = this.processSuccess.createDelegate(this);
11941     /**
11942      * @private
11943      */
11944     this.failureDelegate = this.processFailure.createDelegate(this);
11945
11946     if(!this.renderer){
11947      /**
11948       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11949       */
11950     this.renderer = new Roo.UpdateManager.BasicRenderer();
11951     }
11952     
11953     Roo.UpdateManager.superclass.constructor.call(this);
11954 };
11955
11956 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11957     /**
11958      * Get the Element this UpdateManager is bound to
11959      * @return {Roo.Element} The element
11960      */
11961     getEl : function(){
11962         return this.el;
11963     },
11964     /**
11965      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11966      * @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:
11967 <pre><code>
11968 um.update({<br/>
11969     url: "your-url.php",<br/>
11970     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11971     callback: yourFunction,<br/>
11972     scope: yourObject, //(optional scope)  <br/>
11973     discardUrl: false, <br/>
11974     nocache: false,<br/>
11975     text: "Loading...",<br/>
11976     timeout: 30,<br/>
11977     scripts: false<br/>
11978 });
11979 </code></pre>
11980      * The only required property is url. The optional properties nocache, text and scripts
11981      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11982      * @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}
11983      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11984      * @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.
11985      */
11986     update : function(url, params, callback, discardUrl){
11987         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11988             var method = this.method,
11989                 cfg;
11990             if(typeof url == "object"){ // must be config object
11991                 cfg = url;
11992                 url = cfg.url;
11993                 params = params || cfg.params;
11994                 callback = callback || cfg.callback;
11995                 discardUrl = discardUrl || cfg.discardUrl;
11996                 if(callback && cfg.scope){
11997                     callback = callback.createDelegate(cfg.scope);
11998                 }
11999                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12000                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12001                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12002                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12003                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12004             }
12005             this.showLoading();
12006             if(!discardUrl){
12007                 this.defaultUrl = url;
12008             }
12009             if(typeof url == "function"){
12010                 url = url.call(this);
12011             }
12012
12013             method = method || (params ? "POST" : "GET");
12014             if(method == "GET"){
12015                 url = this.prepareUrl(url);
12016             }
12017
12018             var o = Roo.apply(cfg ||{}, {
12019                 url : url,
12020                 params: params,
12021                 success: this.successDelegate,
12022                 failure: this.failureDelegate,
12023                 callback: undefined,
12024                 timeout: (this.timeout*1000),
12025                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12026             });
12027             Roo.log("updated manager called with timeout of " + o.timeout);
12028             this.transaction = Roo.Ajax.request(o);
12029         }
12030     },
12031
12032     /**
12033      * 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.
12034      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12035      * @param {String/HTMLElement} form The form Id or form element
12036      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12037      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12038      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12039      */
12040     formUpdate : function(form, url, reset, callback){
12041         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12042             if(typeof url == "function"){
12043                 url = url.call(this);
12044             }
12045             form = Roo.getDom(form);
12046             this.transaction = Roo.Ajax.request({
12047                 form: form,
12048                 url:url,
12049                 success: this.successDelegate,
12050                 failure: this.failureDelegate,
12051                 timeout: (this.timeout*1000),
12052                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12053             });
12054             this.showLoading.defer(1, this);
12055         }
12056     },
12057
12058     /**
12059      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12060      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12061      */
12062     refresh : function(callback){
12063         if(this.defaultUrl == null){
12064             return;
12065         }
12066         this.update(this.defaultUrl, null, callback, true);
12067     },
12068
12069     /**
12070      * Set this element to auto refresh.
12071      * @param {Number} interval How often to update (in seconds).
12072      * @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)
12073      * @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}
12074      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12075      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12076      */
12077     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12078         if(refreshNow){
12079             this.update(url || this.defaultUrl, params, callback, true);
12080         }
12081         if(this.autoRefreshProcId){
12082             clearInterval(this.autoRefreshProcId);
12083         }
12084         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12085     },
12086
12087     /**
12088      * Stop auto refresh on this element.
12089      */
12090      stopAutoRefresh : function(){
12091         if(this.autoRefreshProcId){
12092             clearInterval(this.autoRefreshProcId);
12093             delete this.autoRefreshProcId;
12094         }
12095     },
12096
12097     isAutoRefreshing : function(){
12098        return this.autoRefreshProcId ? true : false;
12099     },
12100     /**
12101      * Called to update the element to "Loading" state. Override to perform custom action.
12102      */
12103     showLoading : function(){
12104         if(this.showLoadIndicator){
12105             this.el.update(this.indicatorText);
12106         }
12107     },
12108
12109     /**
12110      * Adds unique parameter to query string if disableCaching = true
12111      * @private
12112      */
12113     prepareUrl : function(url){
12114         if(this.disableCaching){
12115             var append = "_dc=" + (new Date().getTime());
12116             if(url.indexOf("?") !== -1){
12117                 url += "&" + append;
12118             }else{
12119                 url += "?" + append;
12120             }
12121         }
12122         return url;
12123     },
12124
12125     /**
12126      * @private
12127      */
12128     processSuccess : function(response){
12129         this.transaction = null;
12130         if(response.argument.form && response.argument.reset){
12131             try{ // put in try/catch since some older FF releases had problems with this
12132                 response.argument.form.reset();
12133             }catch(e){}
12134         }
12135         if(this.loadScripts){
12136             this.renderer.render(this.el, response, this,
12137                 this.updateComplete.createDelegate(this, [response]));
12138         }else{
12139             this.renderer.render(this.el, response, this);
12140             this.updateComplete(response);
12141         }
12142     },
12143
12144     updateComplete : function(response){
12145         this.fireEvent("update", this.el, response);
12146         if(typeof response.argument.callback == "function"){
12147             response.argument.callback(this.el, true, response);
12148         }
12149     },
12150
12151     /**
12152      * @private
12153      */
12154     processFailure : function(response){
12155         this.transaction = null;
12156         this.fireEvent("failure", this.el, response);
12157         if(typeof response.argument.callback == "function"){
12158             response.argument.callback(this.el, false, response);
12159         }
12160     },
12161
12162     /**
12163      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12164      * @param {Object} renderer The object implementing the render() method
12165      */
12166     setRenderer : function(renderer){
12167         this.renderer = renderer;
12168     },
12169
12170     getRenderer : function(){
12171        return this.renderer;
12172     },
12173
12174     /**
12175      * Set the defaultUrl used for updates
12176      * @param {String/Function} defaultUrl The url or a function to call to get the url
12177      */
12178     setDefaultUrl : function(defaultUrl){
12179         this.defaultUrl = defaultUrl;
12180     },
12181
12182     /**
12183      * Aborts the executing transaction
12184      */
12185     abort : function(){
12186         if(this.transaction){
12187             Roo.Ajax.abort(this.transaction);
12188         }
12189     },
12190
12191     /**
12192      * Returns true if an update is in progress
12193      * @return {Boolean}
12194      */
12195     isUpdating : function(){
12196         if(this.transaction){
12197             return Roo.Ajax.isLoading(this.transaction);
12198         }
12199         return false;
12200     }
12201 });
12202
12203 /**
12204  * @class Roo.UpdateManager.defaults
12205  * @static (not really - but it helps the doc tool)
12206  * The defaults collection enables customizing the default properties of UpdateManager
12207  */
12208    Roo.UpdateManager.defaults = {
12209        /**
12210          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12211          * @type Number
12212          */
12213          timeout : 30,
12214
12215          /**
12216          * True to process scripts by default (Defaults to false).
12217          * @type Boolean
12218          */
12219         loadScripts : false,
12220
12221         /**
12222         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12223         * @type String
12224         */
12225         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12226         /**
12227          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12228          * @type Boolean
12229          */
12230         disableCaching : false,
12231         /**
12232          * Whether to show indicatorText when loading (Defaults to true).
12233          * @type Boolean
12234          */
12235         showLoadIndicator : true,
12236         /**
12237          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12238          * @type String
12239          */
12240         indicatorText : '<div class="loading-indicator">Loading...</div>'
12241    };
12242
12243 /**
12244  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12245  *Usage:
12246  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12247  * @param {String/HTMLElement/Roo.Element} el The element to update
12248  * @param {String} url The url
12249  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12250  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12251  * @static
12252  * @deprecated
12253  * @member Roo.UpdateManager
12254  */
12255 Roo.UpdateManager.updateElement = function(el, url, params, options){
12256     var um = Roo.get(el, true).getUpdateManager();
12257     Roo.apply(um, options);
12258     um.update(url, params, options ? options.callback : null);
12259 };
12260 // alias for backwards compat
12261 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12262 /**
12263  * @class Roo.UpdateManager.BasicRenderer
12264  * Default Content renderer. Updates the elements innerHTML with the responseText.
12265  */
12266 Roo.UpdateManager.BasicRenderer = function(){};
12267
12268 Roo.UpdateManager.BasicRenderer.prototype = {
12269     /**
12270      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12271      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12272      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12273      * @param {Roo.Element} el The element being rendered
12274      * @param {Object} response The YUI Connect response object
12275      * @param {UpdateManager} updateManager The calling update manager
12276      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12277      */
12278      render : function(el, response, updateManager, callback){
12279         el.update(response.responseText, updateManager.loadScripts, callback);
12280     }
12281 };
12282 /*
12283  * Based on:
12284  * Roo JS
12285  * (c)) Alan Knowles
12286  * Licence : LGPL
12287  */
12288
12289
12290 /**
12291  * @class Roo.DomTemplate
12292  * @extends Roo.Template
12293  * An effort at a dom based template engine..
12294  *
12295  * Similar to XTemplate, except it uses dom parsing to create the template..
12296  *
12297  * Supported features:
12298  *
12299  *  Tags:
12300
12301 <pre><code>
12302       {a_variable} - output encoded.
12303       {a_variable.format:("Y-m-d")} - call a method on the variable
12304       {a_variable:raw} - unencoded output
12305       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12306       {a_variable:this.method_on_template(...)} - call a method on the template object.
12307  
12308 </code></pre>
12309  *  The tpl tag:
12310 <pre><code>
12311         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12312         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12313         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12314         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12315   
12316 </code></pre>
12317  *      
12318  */
12319 Roo.DomTemplate = function()
12320 {
12321      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12322      if (this.html) {
12323         this.compile();
12324      }
12325 };
12326
12327
12328 Roo.extend(Roo.DomTemplate, Roo.Template, {
12329     /**
12330      * id counter for sub templates.
12331      */
12332     id : 0,
12333     /**
12334      * flag to indicate if dom parser is inside a pre,
12335      * it will strip whitespace if not.
12336      */
12337     inPre : false,
12338     
12339     /**
12340      * The various sub templates
12341      */
12342     tpls : false,
12343     
12344     
12345     
12346     /**
12347      *
12348      * basic tag replacing syntax
12349      * WORD:WORD()
12350      *
12351      * // you can fake an object call by doing this
12352      *  x.t:(test,tesT) 
12353      * 
12354      */
12355     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12356     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12357     
12358     iterChild : function (node, method) {
12359         
12360         var oldPre = this.inPre;
12361         if (node.tagName == 'PRE') {
12362             this.inPre = true;
12363         }
12364         for( var i = 0; i < node.childNodes.length; i++) {
12365             method.call(this, node.childNodes[i]);
12366         }
12367         this.inPre = oldPre;
12368     },
12369     
12370     
12371     
12372     /**
12373      * compile the template
12374      *
12375      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12376      *
12377      */
12378     compile: function()
12379     {
12380         var s = this.html;
12381         
12382         // covert the html into DOM...
12383         var doc = false;
12384         var div =false;
12385         try {
12386             doc = document.implementation.createHTMLDocument("");
12387             doc.documentElement.innerHTML =   this.html  ;
12388             div = doc.documentElement;
12389         } catch (e) {
12390             // old IE... - nasty -- it causes all sorts of issues.. with
12391             // images getting pulled from server..
12392             div = document.createElement('div');
12393             div.innerHTML = this.html;
12394         }
12395         //doc.documentElement.innerHTML = htmlBody
12396          
12397         
12398         
12399         this.tpls = [];
12400         var _t = this;
12401         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12402         
12403         var tpls = this.tpls;
12404         
12405         // create a top level template from the snippet..
12406         
12407         //Roo.log(div.innerHTML);
12408         
12409         var tpl = {
12410             uid : 'master',
12411             id : this.id++,
12412             attr : false,
12413             value : false,
12414             body : div.innerHTML,
12415             
12416             forCall : false,
12417             execCall : false,
12418             dom : div,
12419             isTop : true
12420             
12421         };
12422         tpls.unshift(tpl);
12423         
12424         
12425         // compile them...
12426         this.tpls = [];
12427         Roo.each(tpls, function(tp){
12428             this.compileTpl(tp);
12429             this.tpls[tp.id] = tp;
12430         }, this);
12431         
12432         this.master = tpls[0];
12433         return this;
12434         
12435         
12436     },
12437     
12438     compileNode : function(node, istop) {
12439         // test for
12440         //Roo.log(node);
12441         
12442         
12443         // skip anything not a tag..
12444         if (node.nodeType != 1) {
12445             if (node.nodeType == 3 && !this.inPre) {
12446                 // reduce white space..
12447                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12448                 
12449             }
12450             return;
12451         }
12452         
12453         var tpl = {
12454             uid : false,
12455             id : false,
12456             attr : false,
12457             value : false,
12458             body : '',
12459             
12460             forCall : false,
12461             execCall : false,
12462             dom : false,
12463             isTop : istop
12464             
12465             
12466         };
12467         
12468         
12469         switch(true) {
12470             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12471             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12472             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12473             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12474             // no default..
12475         }
12476         
12477         
12478         if (!tpl.attr) {
12479             // just itterate children..
12480             this.iterChild(node,this.compileNode);
12481             return;
12482         }
12483         tpl.uid = this.id++;
12484         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12485         node.removeAttribute('roo-'+ tpl.attr);
12486         if (tpl.attr != 'name') {
12487             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12488             node.parentNode.replaceChild(placeholder,  node);
12489         } else {
12490             
12491             var placeholder =  document.createElement('span');
12492             placeholder.className = 'roo-tpl-' + tpl.value;
12493             node.parentNode.replaceChild(placeholder,  node);
12494         }
12495         
12496         // parent now sees '{domtplXXXX}
12497         this.iterChild(node,this.compileNode);
12498         
12499         // we should now have node body...
12500         var div = document.createElement('div');
12501         div.appendChild(node);
12502         tpl.dom = node;
12503         // this has the unfortunate side effect of converting tagged attributes
12504         // eg. href="{...}" into %7C...%7D
12505         // this has been fixed by searching for those combo's although it's a bit hacky..
12506         
12507         
12508         tpl.body = div.innerHTML;
12509         
12510         
12511          
12512         tpl.id = tpl.uid;
12513         switch(tpl.attr) {
12514             case 'for' :
12515                 switch (tpl.value) {
12516                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12517                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12518                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12519                 }
12520                 break;
12521             
12522             case 'exec':
12523                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12524                 break;
12525             
12526             case 'if':     
12527                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12528                 break;
12529             
12530             case 'name':
12531                 tpl.id  = tpl.value; // replace non characters???
12532                 break;
12533             
12534         }
12535         
12536         
12537         this.tpls.push(tpl);
12538         
12539         
12540         
12541     },
12542     
12543     
12544     
12545     
12546     /**
12547      * Compile a segment of the template into a 'sub-template'
12548      *
12549      * 
12550      * 
12551      *
12552      */
12553     compileTpl : function(tpl)
12554     {
12555         var fm = Roo.util.Format;
12556         var useF = this.disableFormats !== true;
12557         
12558         var sep = Roo.isGecko ? "+\n" : ",\n";
12559         
12560         var undef = function(str) {
12561             Roo.debug && Roo.log("Property not found :"  + str);
12562             return '';
12563         };
12564           
12565         //Roo.log(tpl.body);
12566         
12567         
12568         
12569         var fn = function(m, lbrace, name, format, args)
12570         {
12571             //Roo.log("ARGS");
12572             //Roo.log(arguments);
12573             args = args ? args.replace(/\\'/g,"'") : args;
12574             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12575             if (typeof(format) == 'undefined') {
12576                 format =  'htmlEncode'; 
12577             }
12578             if (format == 'raw' ) {
12579                 format = false;
12580             }
12581             
12582             if(name.substr(0, 6) == 'domtpl'){
12583                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12584             }
12585             
12586             // build an array of options to determine if value is undefined..
12587             
12588             // basically get 'xxxx.yyyy' then do
12589             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12590             //    (function () { Roo.log("Property not found"); return ''; })() :
12591             //    ......
12592             
12593             var udef_ar = [];
12594             var lookfor = '';
12595             Roo.each(name.split('.'), function(st) {
12596                 lookfor += (lookfor.length ? '.': '') + st;
12597                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12598             });
12599             
12600             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12601             
12602             
12603             if(format && useF){
12604                 
12605                 args = args ? ',' + args : "";
12606                  
12607                 if(format.substr(0, 5) != "this."){
12608                     format = "fm." + format + '(';
12609                 }else{
12610                     format = 'this.call("'+ format.substr(5) + '", ';
12611                     args = ", values";
12612                 }
12613                 
12614                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12615             }
12616              
12617             if (args && args.length) {
12618                 // called with xxyx.yuu:(test,test)
12619                 // change to ()
12620                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12621             }
12622             // raw.. - :raw modifier..
12623             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12624             
12625         };
12626         var body;
12627         // branched to use + in gecko and [].join() in others
12628         if(Roo.isGecko){
12629             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12630                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12631                     "';};};";
12632         }else{
12633             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12634             body.push(tpl.body.replace(/(\r\n|\n)/g,
12635                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12636             body.push("'].join('');};};");
12637             body = body.join('');
12638         }
12639         
12640         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12641        
12642         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12643         eval(body);
12644         
12645         return this;
12646     },
12647      
12648     /**
12649      * same as applyTemplate, except it's done to one of the subTemplates
12650      * when using named templates, you can do:
12651      *
12652      * var str = pl.applySubTemplate('your-name', values);
12653      *
12654      * 
12655      * @param {Number} id of the template
12656      * @param {Object} values to apply to template
12657      * @param {Object} parent (normaly the instance of this object)
12658      */
12659     applySubTemplate : function(id, values, parent)
12660     {
12661         
12662         
12663         var t = this.tpls[id];
12664         
12665         
12666         try { 
12667             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12668                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12669                 return '';
12670             }
12671         } catch(e) {
12672             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12673             Roo.log(values);
12674           
12675             return '';
12676         }
12677         try { 
12678             
12679             if(t.execCall && t.execCall.call(this, values, parent)){
12680                 return '';
12681             }
12682         } catch(e) {
12683             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12684             Roo.log(values);
12685             return '';
12686         }
12687         
12688         try {
12689             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12690             parent = t.target ? values : parent;
12691             if(t.forCall && vs instanceof Array){
12692                 var buf = [];
12693                 for(var i = 0, len = vs.length; i < len; i++){
12694                     try {
12695                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12696                     } catch (e) {
12697                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12698                         Roo.log(e.body);
12699                         //Roo.log(t.compiled);
12700                         Roo.log(vs[i]);
12701                     }   
12702                 }
12703                 return buf.join('');
12704             }
12705         } catch (e) {
12706             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12707             Roo.log(values);
12708             return '';
12709         }
12710         try {
12711             return t.compiled.call(this, vs, parent);
12712         } catch (e) {
12713             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12714             Roo.log(e.body);
12715             //Roo.log(t.compiled);
12716             Roo.log(values);
12717             return '';
12718         }
12719     },
12720
12721    
12722
12723     applyTemplate : function(values){
12724         return this.master.compiled.call(this, values, {});
12725         //var s = this.subs;
12726     },
12727
12728     apply : function(){
12729         return this.applyTemplate.apply(this, arguments);
12730     }
12731
12732  });
12733
12734 Roo.DomTemplate.from = function(el){
12735     el = Roo.getDom(el);
12736     return new Roo.Domtemplate(el.value || el.innerHTML);
12737 };/*
12738  * Based on:
12739  * Ext JS Library 1.1.1
12740  * Copyright(c) 2006-2007, Ext JS, LLC.
12741  *
12742  * Originally Released Under LGPL - original licence link has changed is not relivant.
12743  *
12744  * Fork - LGPL
12745  * <script type="text/javascript">
12746  */
12747
12748 /**
12749  * @class Roo.util.DelayedTask
12750  * Provides a convenient method of performing setTimeout where a new
12751  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12752  * You can use this class to buffer
12753  * the keypress events for a certain number of milliseconds, and perform only if they stop
12754  * for that amount of time.
12755  * @constructor The parameters to this constructor serve as defaults and are not required.
12756  * @param {Function} fn (optional) The default function to timeout
12757  * @param {Object} scope (optional) The default scope of that timeout
12758  * @param {Array} args (optional) The default Array of arguments
12759  */
12760 Roo.util.DelayedTask = function(fn, scope, args){
12761     var id = null, d, t;
12762
12763     var call = function(){
12764         var now = new Date().getTime();
12765         if(now - t >= d){
12766             clearInterval(id);
12767             id = null;
12768             fn.apply(scope, args || []);
12769         }
12770     };
12771     /**
12772      * Cancels any pending timeout and queues a new one
12773      * @param {Number} delay The milliseconds to delay
12774      * @param {Function} newFn (optional) Overrides function passed to constructor
12775      * @param {Object} newScope (optional) Overrides scope passed to constructor
12776      * @param {Array} newArgs (optional) Overrides args passed to constructor
12777      */
12778     this.delay = function(delay, newFn, newScope, newArgs){
12779         if(id && delay != d){
12780             this.cancel();
12781         }
12782         d = delay;
12783         t = new Date().getTime();
12784         fn = newFn || fn;
12785         scope = newScope || scope;
12786         args = newArgs || args;
12787         if(!id){
12788             id = setInterval(call, d);
12789         }
12790     };
12791
12792     /**
12793      * Cancel the last queued timeout
12794      */
12795     this.cancel = function(){
12796         if(id){
12797             clearInterval(id);
12798             id = null;
12799         }
12800     };
12801 };/*
12802  * Based on:
12803  * Ext JS Library 1.1.1
12804  * Copyright(c) 2006-2007, Ext JS, LLC.
12805  *
12806  * Originally Released Under LGPL - original licence link has changed is not relivant.
12807  *
12808  * Fork - LGPL
12809  * <script type="text/javascript">
12810  */
12811  
12812  
12813 Roo.util.TaskRunner = function(interval){
12814     interval = interval || 10;
12815     var tasks = [], removeQueue = [];
12816     var id = 0;
12817     var running = false;
12818
12819     var stopThread = function(){
12820         running = false;
12821         clearInterval(id);
12822         id = 0;
12823     };
12824
12825     var startThread = function(){
12826         if(!running){
12827             running = true;
12828             id = setInterval(runTasks, interval);
12829         }
12830     };
12831
12832     var removeTask = function(task){
12833         removeQueue.push(task);
12834         if(task.onStop){
12835             task.onStop();
12836         }
12837     };
12838
12839     var runTasks = function(){
12840         if(removeQueue.length > 0){
12841             for(var i = 0, len = removeQueue.length; i < len; i++){
12842                 tasks.remove(removeQueue[i]);
12843             }
12844             removeQueue = [];
12845             if(tasks.length < 1){
12846                 stopThread();
12847                 return;
12848             }
12849         }
12850         var now = new Date().getTime();
12851         for(var i = 0, len = tasks.length; i < len; ++i){
12852             var t = tasks[i];
12853             var itime = now - t.taskRunTime;
12854             if(t.interval <= itime){
12855                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12856                 t.taskRunTime = now;
12857                 if(rt === false || t.taskRunCount === t.repeat){
12858                     removeTask(t);
12859                     return;
12860                 }
12861             }
12862             if(t.duration && t.duration <= (now - t.taskStartTime)){
12863                 removeTask(t);
12864             }
12865         }
12866     };
12867
12868     /**
12869      * Queues a new task.
12870      * @param {Object} task
12871      */
12872     this.start = function(task){
12873         tasks.push(task);
12874         task.taskStartTime = new Date().getTime();
12875         task.taskRunTime = 0;
12876         task.taskRunCount = 0;
12877         startThread();
12878         return task;
12879     };
12880
12881     this.stop = function(task){
12882         removeTask(task);
12883         return task;
12884     };
12885
12886     this.stopAll = function(){
12887         stopThread();
12888         for(var i = 0, len = tasks.length; i < len; i++){
12889             if(tasks[i].onStop){
12890                 tasks[i].onStop();
12891             }
12892         }
12893         tasks = [];
12894         removeQueue = [];
12895     };
12896 };
12897
12898 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12899  * Based on:
12900  * Ext JS Library 1.1.1
12901  * Copyright(c) 2006-2007, Ext JS, LLC.
12902  *
12903  * Originally Released Under LGPL - original licence link has changed is not relivant.
12904  *
12905  * Fork - LGPL
12906  * <script type="text/javascript">
12907  */
12908
12909  
12910 /**
12911  * @class Roo.util.MixedCollection
12912  * @extends Roo.util.Observable
12913  * A Collection class that maintains both numeric indexes and keys and exposes events.
12914  * @constructor
12915  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12916  * collection (defaults to false)
12917  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12918  * and return the key value for that item.  This is used when available to look up the key on items that
12919  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12920  * equivalent to providing an implementation for the {@link #getKey} method.
12921  */
12922 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12923     this.items = [];
12924     this.map = {};
12925     this.keys = [];
12926     this.length = 0;
12927     this.addEvents({
12928         /**
12929          * @event clear
12930          * Fires when the collection is cleared.
12931          */
12932         "clear" : true,
12933         /**
12934          * @event add
12935          * Fires when an item is added to the collection.
12936          * @param {Number} index The index at which the item was added.
12937          * @param {Object} o The item added.
12938          * @param {String} key The key associated with the added item.
12939          */
12940         "add" : true,
12941         /**
12942          * @event replace
12943          * Fires when an item is replaced in the collection.
12944          * @param {String} key he key associated with the new added.
12945          * @param {Object} old The item being replaced.
12946          * @param {Object} new The new item.
12947          */
12948         "replace" : true,
12949         /**
12950          * @event remove
12951          * Fires when an item is removed from the collection.
12952          * @param {Object} o The item being removed.
12953          * @param {String} key (optional) The key associated with the removed item.
12954          */
12955         "remove" : true,
12956         "sort" : true
12957     });
12958     this.allowFunctions = allowFunctions === true;
12959     if(keyFn){
12960         this.getKey = keyFn;
12961     }
12962     Roo.util.MixedCollection.superclass.constructor.call(this);
12963 };
12964
12965 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12966     allowFunctions : false,
12967     
12968 /**
12969  * Adds an item to the collection.
12970  * @param {String} key The key to associate with the item
12971  * @param {Object} o The item to add.
12972  * @return {Object} The item added.
12973  */
12974     add : function(key, o){
12975         if(arguments.length == 1){
12976             o = arguments[0];
12977             key = this.getKey(o);
12978         }
12979         if(typeof key == "undefined" || key === null){
12980             this.length++;
12981             this.items.push(o);
12982             this.keys.push(null);
12983         }else{
12984             var old = this.map[key];
12985             if(old){
12986                 return this.replace(key, o);
12987             }
12988             this.length++;
12989             this.items.push(o);
12990             this.map[key] = o;
12991             this.keys.push(key);
12992         }
12993         this.fireEvent("add", this.length-1, o, key);
12994         return o;
12995     },
12996        
12997 /**
12998   * MixedCollection has a generic way to fetch keys if you implement getKey.
12999 <pre><code>
13000 // normal way
13001 var mc = new Roo.util.MixedCollection();
13002 mc.add(someEl.dom.id, someEl);
13003 mc.add(otherEl.dom.id, otherEl);
13004 //and so on
13005
13006 // using getKey
13007 var mc = new Roo.util.MixedCollection();
13008 mc.getKey = function(el){
13009    return el.dom.id;
13010 };
13011 mc.add(someEl);
13012 mc.add(otherEl);
13013
13014 // or via the constructor
13015 var mc = new Roo.util.MixedCollection(false, function(el){
13016    return el.dom.id;
13017 });
13018 mc.add(someEl);
13019 mc.add(otherEl);
13020 </code></pre>
13021  * @param o {Object} The item for which to find the key.
13022  * @return {Object} The key for the passed item.
13023  */
13024     getKey : function(o){
13025          return o.id; 
13026     },
13027    
13028 /**
13029  * Replaces an item in the collection.
13030  * @param {String} key The key associated with the item to replace, or the item to replace.
13031  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13032  * @return {Object}  The new item.
13033  */
13034     replace : function(key, o){
13035         if(arguments.length == 1){
13036             o = arguments[0];
13037             key = this.getKey(o);
13038         }
13039         var old = this.item(key);
13040         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13041              return this.add(key, o);
13042         }
13043         var index = this.indexOfKey(key);
13044         this.items[index] = o;
13045         this.map[key] = o;
13046         this.fireEvent("replace", key, old, o);
13047         return o;
13048     },
13049    
13050 /**
13051  * Adds all elements of an Array or an Object to the collection.
13052  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13053  * an Array of values, each of which are added to the collection.
13054  */
13055     addAll : function(objs){
13056         if(arguments.length > 1 || objs instanceof Array){
13057             var args = arguments.length > 1 ? arguments : objs;
13058             for(var i = 0, len = args.length; i < len; i++){
13059                 this.add(args[i]);
13060             }
13061         }else{
13062             for(var key in objs){
13063                 if(this.allowFunctions || typeof objs[key] != "function"){
13064                     this.add(key, objs[key]);
13065                 }
13066             }
13067         }
13068     },
13069    
13070 /**
13071  * Executes the specified function once for every item in the collection, passing each
13072  * item as the first and only parameter. returning false from the function will stop the iteration.
13073  * @param {Function} fn The function to execute for each item.
13074  * @param {Object} scope (optional) The scope in which to execute the function.
13075  */
13076     each : function(fn, scope){
13077         var items = [].concat(this.items); // each safe for removal
13078         for(var i = 0, len = items.length; i < len; i++){
13079             if(fn.call(scope || items[i], items[i], i, len) === false){
13080                 break;
13081             }
13082         }
13083     },
13084    
13085 /**
13086  * Executes the specified function once for every key in the collection, passing each
13087  * key, and its associated item as the first two parameters.
13088  * @param {Function} fn The function to execute for each item.
13089  * @param {Object} scope (optional) The scope in which to execute the function.
13090  */
13091     eachKey : function(fn, scope){
13092         for(var i = 0, len = this.keys.length; i < len; i++){
13093             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13094         }
13095     },
13096    
13097 /**
13098  * Returns the first item in the collection which elicits a true return value from the
13099  * passed selection function.
13100  * @param {Function} fn The selection function to execute for each item.
13101  * @param {Object} scope (optional) The scope in which to execute the function.
13102  * @return {Object} The first item in the collection which returned true from the selection function.
13103  */
13104     find : function(fn, scope){
13105         for(var i = 0, len = this.items.length; i < len; i++){
13106             if(fn.call(scope || window, this.items[i], this.keys[i])){
13107                 return this.items[i];
13108             }
13109         }
13110         return null;
13111     },
13112    
13113 /**
13114  * Inserts an item at the specified index in the collection.
13115  * @param {Number} index The index to insert the item at.
13116  * @param {String} key The key to associate with the new item, or the item itself.
13117  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13118  * @return {Object} The item inserted.
13119  */
13120     insert : function(index, key, o){
13121         if(arguments.length == 2){
13122             o = arguments[1];
13123             key = this.getKey(o);
13124         }
13125         if(index >= this.length){
13126             return this.add(key, o);
13127         }
13128         this.length++;
13129         this.items.splice(index, 0, o);
13130         if(typeof key != "undefined" && key != null){
13131             this.map[key] = o;
13132         }
13133         this.keys.splice(index, 0, key);
13134         this.fireEvent("add", index, o, key);
13135         return o;
13136     },
13137    
13138 /**
13139  * Removed an item from the collection.
13140  * @param {Object} o The item to remove.
13141  * @return {Object} The item removed.
13142  */
13143     remove : function(o){
13144         return this.removeAt(this.indexOf(o));
13145     },
13146    
13147 /**
13148  * Remove an item from a specified index in the collection.
13149  * @param {Number} index The index within the collection of the item to remove.
13150  */
13151     removeAt : function(index){
13152         if(index < this.length && index >= 0){
13153             this.length--;
13154             var o = this.items[index];
13155             this.items.splice(index, 1);
13156             var key = this.keys[index];
13157             if(typeof key != "undefined"){
13158                 delete this.map[key];
13159             }
13160             this.keys.splice(index, 1);
13161             this.fireEvent("remove", o, key);
13162         }
13163     },
13164    
13165 /**
13166  * Removed an item associated with the passed key fom the collection.
13167  * @param {String} key The key of the item to remove.
13168  */
13169     removeKey : function(key){
13170         return this.removeAt(this.indexOfKey(key));
13171     },
13172    
13173 /**
13174  * Returns the number of items in the collection.
13175  * @return {Number} the number of items in the collection.
13176  */
13177     getCount : function(){
13178         return this.length; 
13179     },
13180    
13181 /**
13182  * Returns index within the collection of the passed Object.
13183  * @param {Object} o The item to find the index of.
13184  * @return {Number} index of the item.
13185  */
13186     indexOf : function(o){
13187         if(!this.items.indexOf){
13188             for(var i = 0, len = this.items.length; i < len; i++){
13189                 if(this.items[i] == o) {
13190                     return i;
13191                 }
13192             }
13193             return -1;
13194         }else{
13195             return this.items.indexOf(o);
13196         }
13197     },
13198    
13199 /**
13200  * Returns index within the collection of the passed key.
13201  * @param {String} key The key to find the index of.
13202  * @return {Number} index of the key.
13203  */
13204     indexOfKey : function(key){
13205         if(!this.keys.indexOf){
13206             for(var i = 0, len = this.keys.length; i < len; i++){
13207                 if(this.keys[i] == key) {
13208                     return i;
13209                 }
13210             }
13211             return -1;
13212         }else{
13213             return this.keys.indexOf(key);
13214         }
13215     },
13216    
13217 /**
13218  * Returns the item associated with the passed key OR index. Key has priority over index.
13219  * @param {String/Number} key The key or index of the item.
13220  * @return {Object} The item associated with the passed key.
13221  */
13222     item : function(key){
13223         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13224         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13225     },
13226     
13227 /**
13228  * Returns the item at the specified index.
13229  * @param {Number} index The index of the item.
13230  * @return {Object}
13231  */
13232     itemAt : function(index){
13233         return this.items[index];
13234     },
13235     
13236 /**
13237  * Returns the item associated with the passed key.
13238  * @param {String/Number} key The key of the item.
13239  * @return {Object} The item associated with the passed key.
13240  */
13241     key : function(key){
13242         return this.map[key];
13243     },
13244    
13245 /**
13246  * Returns true if the collection contains the passed Object as an item.
13247  * @param {Object} o  The Object to look for in the collection.
13248  * @return {Boolean} True if the collection contains the Object as an item.
13249  */
13250     contains : function(o){
13251         return this.indexOf(o) != -1;
13252     },
13253    
13254 /**
13255  * Returns true if the collection contains the passed Object as a key.
13256  * @param {String} key The key to look for in the collection.
13257  * @return {Boolean} True if the collection contains the Object as a key.
13258  */
13259     containsKey : function(key){
13260         return typeof this.map[key] != "undefined";
13261     },
13262    
13263 /**
13264  * Removes all items from the collection.
13265  */
13266     clear : function(){
13267         this.length = 0;
13268         this.items = [];
13269         this.keys = [];
13270         this.map = {};
13271         this.fireEvent("clear");
13272     },
13273    
13274 /**
13275  * Returns the first item in the collection.
13276  * @return {Object} the first item in the collection..
13277  */
13278     first : function(){
13279         return this.items[0]; 
13280     },
13281    
13282 /**
13283  * Returns the last item in the collection.
13284  * @return {Object} the last item in the collection..
13285  */
13286     last : function(){
13287         return this.items[this.length-1];   
13288     },
13289     
13290     _sort : function(property, dir, fn){
13291         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13292         fn = fn || function(a, b){
13293             return a-b;
13294         };
13295         var c = [], k = this.keys, items = this.items;
13296         for(var i = 0, len = items.length; i < len; i++){
13297             c[c.length] = {key: k[i], value: items[i], index: i};
13298         }
13299         c.sort(function(a, b){
13300             var v = fn(a[property], b[property]) * dsc;
13301             if(v == 0){
13302                 v = (a.index < b.index ? -1 : 1);
13303             }
13304             return v;
13305         });
13306         for(var i = 0, len = c.length; i < len; i++){
13307             items[i] = c[i].value;
13308             k[i] = c[i].key;
13309         }
13310         this.fireEvent("sort", this);
13311     },
13312     
13313     /**
13314      * Sorts this collection with the passed comparison function
13315      * @param {String} direction (optional) "ASC" or "DESC"
13316      * @param {Function} fn (optional) comparison function
13317      */
13318     sort : function(dir, fn){
13319         this._sort("value", dir, fn);
13320     },
13321     
13322     /**
13323      * Sorts this collection by keys
13324      * @param {String} direction (optional) "ASC" or "DESC"
13325      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13326      */
13327     keySort : function(dir, fn){
13328         this._sort("key", dir, fn || function(a, b){
13329             return String(a).toUpperCase()-String(b).toUpperCase();
13330         });
13331     },
13332     
13333     /**
13334      * Returns a range of items in this collection
13335      * @param {Number} startIndex (optional) defaults to 0
13336      * @param {Number} endIndex (optional) default to the last item
13337      * @return {Array} An array of items
13338      */
13339     getRange : function(start, end){
13340         var items = this.items;
13341         if(items.length < 1){
13342             return [];
13343         }
13344         start = start || 0;
13345         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13346         var r = [];
13347         if(start <= end){
13348             for(var i = start; i <= end; i++) {
13349                     r[r.length] = items[i];
13350             }
13351         }else{
13352             for(var i = start; i >= end; i--) {
13353                     r[r.length] = items[i];
13354             }
13355         }
13356         return r;
13357     },
13358         
13359     /**
13360      * Filter the <i>objects</i> in this collection by a specific property. 
13361      * Returns a new collection that has been filtered.
13362      * @param {String} property A property on your objects
13363      * @param {String/RegExp} value Either string that the property values 
13364      * should start with or a RegExp to test against the property
13365      * @return {MixedCollection} The new filtered collection
13366      */
13367     filter : function(property, value){
13368         if(!value.exec){ // not a regex
13369             value = String(value);
13370             if(value.length == 0){
13371                 return this.clone();
13372             }
13373             value = new RegExp("^" + Roo.escapeRe(value), "i");
13374         }
13375         return this.filterBy(function(o){
13376             return o && value.test(o[property]);
13377         });
13378         },
13379     
13380     /**
13381      * Filter by a function. * Returns a new collection that has been filtered.
13382      * The passed function will be called with each 
13383      * object in the collection. If the function returns true, the value is included 
13384      * otherwise it is filtered.
13385      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13386      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13387      * @return {MixedCollection} The new filtered collection
13388      */
13389     filterBy : function(fn, scope){
13390         var r = new Roo.util.MixedCollection();
13391         r.getKey = this.getKey;
13392         var k = this.keys, it = this.items;
13393         for(var i = 0, len = it.length; i < len; i++){
13394             if(fn.call(scope||this, it[i], k[i])){
13395                                 r.add(k[i], it[i]);
13396                         }
13397         }
13398         return r;
13399     },
13400     
13401     /**
13402      * Creates a duplicate of this collection
13403      * @return {MixedCollection}
13404      */
13405     clone : function(){
13406         var r = new Roo.util.MixedCollection();
13407         var k = this.keys, it = this.items;
13408         for(var i = 0, len = it.length; i < len; i++){
13409             r.add(k[i], it[i]);
13410         }
13411         r.getKey = this.getKey;
13412         return r;
13413     }
13414 });
13415 /**
13416  * Returns the item associated with the passed key or index.
13417  * @method
13418  * @param {String/Number} key The key or index of the item.
13419  * @return {Object} The item associated with the passed key.
13420  */
13421 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13422  * Based on:
13423  * Ext JS Library 1.1.1
13424  * Copyright(c) 2006-2007, Ext JS, LLC.
13425  *
13426  * Originally Released Under LGPL - original licence link has changed is not relivant.
13427  *
13428  * Fork - LGPL
13429  * <script type="text/javascript">
13430  */
13431 /**
13432  * @class Roo.util.JSON
13433  * Modified version of Douglas Crockford"s json.js that doesn"t
13434  * mess with the Object prototype 
13435  * http://www.json.org/js.html
13436  * @singleton
13437  */
13438 Roo.util.JSON = new (function(){
13439     var useHasOwn = {}.hasOwnProperty ? true : false;
13440     
13441     // crashes Safari in some instances
13442     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13443     
13444     var pad = function(n) {
13445         return n < 10 ? "0" + n : n;
13446     };
13447     
13448     var m = {
13449         "\b": '\\b',
13450         "\t": '\\t',
13451         "\n": '\\n',
13452         "\f": '\\f',
13453         "\r": '\\r',
13454         '"' : '\\"',
13455         "\\": '\\\\'
13456     };
13457
13458     var encodeString = function(s){
13459         if (/["\\\x00-\x1f]/.test(s)) {
13460             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13461                 var c = m[b];
13462                 if(c){
13463                     return c;
13464                 }
13465                 c = b.charCodeAt();
13466                 return "\\u00" +
13467                     Math.floor(c / 16).toString(16) +
13468                     (c % 16).toString(16);
13469             }) + '"';
13470         }
13471         return '"' + s + '"';
13472     };
13473     
13474     var encodeArray = function(o){
13475         var a = ["["], b, i, l = o.length, v;
13476             for (i = 0; i < l; i += 1) {
13477                 v = o[i];
13478                 switch (typeof v) {
13479                     case "undefined":
13480                     case "function":
13481                     case "unknown":
13482                         break;
13483                     default:
13484                         if (b) {
13485                             a.push(',');
13486                         }
13487                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13488                         b = true;
13489                 }
13490             }
13491             a.push("]");
13492             return a.join("");
13493     };
13494     
13495     var encodeDate = function(o){
13496         return '"' + o.getFullYear() + "-" +
13497                 pad(o.getMonth() + 1) + "-" +
13498                 pad(o.getDate()) + "T" +
13499                 pad(o.getHours()) + ":" +
13500                 pad(o.getMinutes()) + ":" +
13501                 pad(o.getSeconds()) + '"';
13502     };
13503     
13504     /**
13505      * Encodes an Object, Array or other value
13506      * @param {Mixed} o The variable to encode
13507      * @return {String} The JSON string
13508      */
13509     this.encode = function(o)
13510     {
13511         // should this be extended to fully wrap stringify..
13512         
13513         if(typeof o == "undefined" || o === null){
13514             return "null";
13515         }else if(o instanceof Array){
13516             return encodeArray(o);
13517         }else if(o instanceof Date){
13518             return encodeDate(o);
13519         }else if(typeof o == "string"){
13520             return encodeString(o);
13521         }else if(typeof o == "number"){
13522             return isFinite(o) ? String(o) : "null";
13523         }else if(typeof o == "boolean"){
13524             return String(o);
13525         }else {
13526             var a = ["{"], b, i, v;
13527             for (i in o) {
13528                 if(!useHasOwn || o.hasOwnProperty(i)) {
13529                     v = o[i];
13530                     switch (typeof v) {
13531                     case "undefined":
13532                     case "function":
13533                     case "unknown":
13534                         break;
13535                     default:
13536                         if(b){
13537                             a.push(',');
13538                         }
13539                         a.push(this.encode(i), ":",
13540                                 v === null ? "null" : this.encode(v));
13541                         b = true;
13542                     }
13543                 }
13544             }
13545             a.push("}");
13546             return a.join("");
13547         }
13548     };
13549     
13550     /**
13551      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13552      * @param {String} json The JSON string
13553      * @return {Object} The resulting object
13554      */
13555     this.decode = function(json){
13556         
13557         return  /** eval:var:json */ eval("(" + json + ')');
13558     };
13559 })();
13560 /** 
13561  * Shorthand for {@link Roo.util.JSON#encode}
13562  * @member Roo encode 
13563  * @method */
13564 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13565 /** 
13566  * Shorthand for {@link Roo.util.JSON#decode}
13567  * @member Roo decode 
13568  * @method */
13569 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13570 /*
13571  * Based on:
13572  * Ext JS Library 1.1.1
13573  * Copyright(c) 2006-2007, Ext JS, LLC.
13574  *
13575  * Originally Released Under LGPL - original licence link has changed is not relivant.
13576  *
13577  * Fork - LGPL
13578  * <script type="text/javascript">
13579  */
13580  
13581 /**
13582  * @class Roo.util.Format
13583  * Reusable data formatting functions
13584  * @singleton
13585  */
13586 Roo.util.Format = function(){
13587     var trimRe = /^\s+|\s+$/g;
13588     return {
13589         /**
13590          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13591          * @param {String} value The string to truncate
13592          * @param {Number} length The maximum length to allow before truncating
13593          * @return {String} The converted text
13594          */
13595         ellipsis : function(value, len){
13596             if(value && value.length > len){
13597                 return value.substr(0, len-3)+"...";
13598             }
13599             return value;
13600         },
13601
13602         /**
13603          * Checks a reference and converts it to empty string if it is undefined
13604          * @param {Mixed} value Reference to check
13605          * @return {Mixed} Empty string if converted, otherwise the original value
13606          */
13607         undef : function(value){
13608             return typeof value != "undefined" ? value : "";
13609         },
13610
13611         /**
13612          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13613          * @param {String} value The string to encode
13614          * @return {String} The encoded text
13615          */
13616         htmlEncode : function(value){
13617             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13618         },
13619
13620         /**
13621          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13622          * @param {String} value The string to decode
13623          * @return {String} The decoded text
13624          */
13625         htmlDecode : function(value){
13626             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13627         },
13628
13629         /**
13630          * Trims any whitespace from either side of a string
13631          * @param {String} value The text to trim
13632          * @return {String} The trimmed text
13633          */
13634         trim : function(value){
13635             return String(value).replace(trimRe, "");
13636         },
13637
13638         /**
13639          * Returns a substring from within an original string
13640          * @param {String} value The original text
13641          * @param {Number} start The start index of the substring
13642          * @param {Number} length The length of the substring
13643          * @return {String} The substring
13644          */
13645         substr : function(value, start, length){
13646             return String(value).substr(start, length);
13647         },
13648
13649         /**
13650          * Converts a string to all lower case letters
13651          * @param {String} value The text to convert
13652          * @return {String} The converted text
13653          */
13654         lowercase : function(value){
13655             return String(value).toLowerCase();
13656         },
13657
13658         /**
13659          * Converts a string to all upper case letters
13660          * @param {String} value The text to convert
13661          * @return {String} The converted text
13662          */
13663         uppercase : function(value){
13664             return String(value).toUpperCase();
13665         },
13666
13667         /**
13668          * Converts the first character only of a string to upper case
13669          * @param {String} value The text to convert
13670          * @return {String} The converted text
13671          */
13672         capitalize : function(value){
13673             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13674         },
13675
13676         // private
13677         call : function(value, fn){
13678             if(arguments.length > 2){
13679                 var args = Array.prototype.slice.call(arguments, 2);
13680                 args.unshift(value);
13681                  
13682                 return /** eval:var:value */  eval(fn).apply(window, args);
13683             }else{
13684                 /** eval:var:value */
13685                 return /** eval:var:value */ eval(fn).call(window, value);
13686             }
13687         },
13688
13689        
13690         /**
13691          * safer version of Math.toFixed..??/
13692          * @param {Number/String} value The numeric value to format
13693          * @param {Number/String} value Decimal places 
13694          * @return {String} The formatted currency string
13695          */
13696         toFixed : function(v, n)
13697         {
13698             // why not use to fixed - precision is buggered???
13699             if (!n) {
13700                 return Math.round(v-0);
13701             }
13702             var fact = Math.pow(10,n+1);
13703             v = (Math.round((v-0)*fact))/fact;
13704             var z = (''+fact).substring(2);
13705             if (v == Math.floor(v)) {
13706                 return Math.floor(v) + '.' + z;
13707             }
13708             
13709             // now just padd decimals..
13710             var ps = String(v).split('.');
13711             var fd = (ps[1] + z);
13712             var r = fd.substring(0,n); 
13713             var rm = fd.substring(n); 
13714             if (rm < 5) {
13715                 return ps[0] + '.' + r;
13716             }
13717             r*=1; // turn it into a number;
13718             r++;
13719             if (String(r).length != n) {
13720                 ps[0]*=1;
13721                 ps[0]++;
13722                 r = String(r).substring(1); // chop the end off.
13723             }
13724             
13725             return ps[0] + '.' + r;
13726              
13727         },
13728         
13729         /**
13730          * Format a number as US currency
13731          * @param {Number/String} value The numeric value to format
13732          * @return {String} The formatted currency string
13733          */
13734         usMoney : function(v){
13735             return '$' + Roo.util.Format.number(v);
13736         },
13737         
13738         /**
13739          * Format a number
13740          * eventually this should probably emulate php's number_format
13741          * @param {Number/String} value The numeric value to format
13742          * @param {Number} decimals number of decimal places
13743          * @return {String} The formatted currency string
13744          */
13745         number : function(v,decimals)
13746         {
13747             // multiply and round.
13748             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13749             var mul = Math.pow(10, decimals);
13750             var zero = String(mul).substring(1);
13751             v = (Math.round((v-0)*mul))/mul;
13752             
13753             // if it's '0' number.. then
13754             
13755             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13756             v = String(v);
13757             var ps = v.split('.');
13758             var whole = ps[0];
13759             
13760             
13761             var r = /(\d+)(\d{3})/;
13762             // add comma's
13763             while (r.test(whole)) {
13764                 whole = whole.replace(r, '$1' + ',' + '$2');
13765             }
13766             
13767             
13768             var sub = ps[1] ?
13769                     // has decimals..
13770                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13771                     // does not have decimals
13772                     (decimals ? ('.' + zero) : '');
13773             
13774             
13775             return whole + sub ;
13776         },
13777         
13778         /**
13779          * Parse a value into a formatted date using the specified format pattern.
13780          * @param {Mixed} value The value to format
13781          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13782          * @return {String} The formatted date string
13783          */
13784         date : function(v, format){
13785             if(!v){
13786                 return "";
13787             }
13788             if(!(v instanceof Date)){
13789                 v = new Date(Date.parse(v));
13790             }
13791             return v.dateFormat(format || Roo.util.Format.defaults.date);
13792         },
13793
13794         /**
13795          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13796          * @param {String} format Any valid date format string
13797          * @return {Function} The date formatting function
13798          */
13799         dateRenderer : function(format){
13800             return function(v){
13801                 return Roo.util.Format.date(v, format);  
13802             };
13803         },
13804
13805         // private
13806         stripTagsRE : /<\/?[^>]+>/gi,
13807         
13808         /**
13809          * Strips all HTML tags
13810          * @param {Mixed} value The text from which to strip tags
13811          * @return {String} The stripped text
13812          */
13813         stripTags : function(v){
13814             return !v ? v : String(v).replace(this.stripTagsRE, "");
13815         }
13816     };
13817 }();
13818 Roo.util.Format.defaults = {
13819     date : 'd/M/Y'
13820 };/*
13821  * Based on:
13822  * Ext JS Library 1.1.1
13823  * Copyright(c) 2006-2007, Ext JS, LLC.
13824  *
13825  * Originally Released Under LGPL - original licence link has changed is not relivant.
13826  *
13827  * Fork - LGPL
13828  * <script type="text/javascript">
13829  */
13830
13831
13832  
13833
13834 /**
13835  * @class Roo.MasterTemplate
13836  * @extends Roo.Template
13837  * Provides a template that can have child templates. The syntax is:
13838 <pre><code>
13839 var t = new Roo.MasterTemplate(
13840         '&lt;select name="{name}"&gt;',
13841                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13842         '&lt;/select&gt;'
13843 );
13844 t.add('options', {value: 'foo', text: 'bar'});
13845 // or you can add multiple child elements in one shot
13846 t.addAll('options', [
13847     {value: 'foo', text: 'bar'},
13848     {value: 'foo2', text: 'bar2'},
13849     {value: 'foo3', text: 'bar3'}
13850 ]);
13851 // then append, applying the master template values
13852 t.append('my-form', {name: 'my-select'});
13853 </code></pre>
13854 * A name attribute for the child template is not required if you have only one child
13855 * template or you want to refer to them by index.
13856  */
13857 Roo.MasterTemplate = function(){
13858     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13859     this.originalHtml = this.html;
13860     var st = {};
13861     var m, re = this.subTemplateRe;
13862     re.lastIndex = 0;
13863     var subIndex = 0;
13864     while(m = re.exec(this.html)){
13865         var name = m[1], content = m[2];
13866         st[subIndex] = {
13867             name: name,
13868             index: subIndex,
13869             buffer: [],
13870             tpl : new Roo.Template(content)
13871         };
13872         if(name){
13873             st[name] = st[subIndex];
13874         }
13875         st[subIndex].tpl.compile();
13876         st[subIndex].tpl.call = this.call.createDelegate(this);
13877         subIndex++;
13878     }
13879     this.subCount = subIndex;
13880     this.subs = st;
13881 };
13882 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13883     /**
13884     * The regular expression used to match sub templates
13885     * @type RegExp
13886     * @property
13887     */
13888     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13889
13890     /**
13891      * Applies the passed values to a child template.
13892      * @param {String/Number} name (optional) The name or index of the child template
13893      * @param {Array/Object} values The values to be applied to the template
13894      * @return {MasterTemplate} this
13895      */
13896      add : function(name, values){
13897         if(arguments.length == 1){
13898             values = arguments[0];
13899             name = 0;
13900         }
13901         var s = this.subs[name];
13902         s.buffer[s.buffer.length] = s.tpl.apply(values);
13903         return this;
13904     },
13905
13906     /**
13907      * Applies all the passed values to a child template.
13908      * @param {String/Number} name (optional) The name or index of the child template
13909      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13910      * @param {Boolean} reset (optional) True to reset the template first
13911      * @return {MasterTemplate} this
13912      */
13913     fill : function(name, values, reset){
13914         var a = arguments;
13915         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13916             values = a[0];
13917             name = 0;
13918             reset = a[1];
13919         }
13920         if(reset){
13921             this.reset();
13922         }
13923         for(var i = 0, len = values.length; i < len; i++){
13924             this.add(name, values[i]);
13925         }
13926         return this;
13927     },
13928
13929     /**
13930      * Resets the template for reuse
13931      * @return {MasterTemplate} this
13932      */
13933      reset : function(){
13934         var s = this.subs;
13935         for(var i = 0; i < this.subCount; i++){
13936             s[i].buffer = [];
13937         }
13938         return this;
13939     },
13940
13941     applyTemplate : function(values){
13942         var s = this.subs;
13943         var replaceIndex = -1;
13944         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13945             return s[++replaceIndex].buffer.join("");
13946         });
13947         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13948     },
13949
13950     apply : function(){
13951         return this.applyTemplate.apply(this, arguments);
13952     },
13953
13954     compile : function(){return this;}
13955 });
13956
13957 /**
13958  * Alias for fill().
13959  * @method
13960  */
13961 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13962  /**
13963  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13964  * var tpl = Roo.MasterTemplate.from('element-id');
13965  * @param {String/HTMLElement} el
13966  * @param {Object} config
13967  * @static
13968  */
13969 Roo.MasterTemplate.from = function(el, config){
13970     el = Roo.getDom(el);
13971     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13972 };/*
13973  * Based on:
13974  * Ext JS Library 1.1.1
13975  * Copyright(c) 2006-2007, Ext JS, LLC.
13976  *
13977  * Originally Released Under LGPL - original licence link has changed is not relivant.
13978  *
13979  * Fork - LGPL
13980  * <script type="text/javascript">
13981  */
13982
13983  
13984 /**
13985  * @class Roo.util.CSS
13986  * Utility class for manipulating CSS rules
13987  * @singleton
13988  */
13989 Roo.util.CSS = function(){
13990         var rules = null;
13991         var doc = document;
13992
13993     var camelRe = /(-[a-z])/gi;
13994     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13995
13996    return {
13997    /**
13998     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13999     * tag and appended to the HEAD of the document.
14000     * @param {String|Object} cssText The text containing the css rules
14001     * @param {String} id An id to add to the stylesheet for later removal
14002     * @return {StyleSheet}
14003     */
14004     createStyleSheet : function(cssText, id){
14005         var ss;
14006         var head = doc.getElementsByTagName("head")[0];
14007         var nrules = doc.createElement("style");
14008         nrules.setAttribute("type", "text/css");
14009         if(id){
14010             nrules.setAttribute("id", id);
14011         }
14012         if (typeof(cssText) != 'string') {
14013             // support object maps..
14014             // not sure if this a good idea.. 
14015             // perhaps it should be merged with the general css handling
14016             // and handle js style props.
14017             var cssTextNew = [];
14018             for(var n in cssText) {
14019                 var citems = [];
14020                 for(var k in cssText[n]) {
14021                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14022                 }
14023                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14024                 
14025             }
14026             cssText = cssTextNew.join("\n");
14027             
14028         }
14029        
14030        
14031        if(Roo.isIE){
14032            head.appendChild(nrules);
14033            ss = nrules.styleSheet;
14034            ss.cssText = cssText;
14035        }else{
14036            try{
14037                 nrules.appendChild(doc.createTextNode(cssText));
14038            }catch(e){
14039                nrules.cssText = cssText; 
14040            }
14041            head.appendChild(nrules);
14042            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14043        }
14044        this.cacheStyleSheet(ss);
14045        return ss;
14046    },
14047
14048    /**
14049     * Removes a style or link tag by id
14050     * @param {String} id The id of the tag
14051     */
14052    removeStyleSheet : function(id){
14053        var existing = doc.getElementById(id);
14054        if(existing){
14055            existing.parentNode.removeChild(existing);
14056        }
14057    },
14058
14059    /**
14060     * Dynamically swaps an existing stylesheet reference for a new one
14061     * @param {String} id The id of an existing link tag to remove
14062     * @param {String} url The href of the new stylesheet to include
14063     */
14064    swapStyleSheet : function(id, url){
14065        this.removeStyleSheet(id);
14066        var ss = doc.createElement("link");
14067        ss.setAttribute("rel", "stylesheet");
14068        ss.setAttribute("type", "text/css");
14069        ss.setAttribute("id", id);
14070        ss.setAttribute("href", url);
14071        doc.getElementsByTagName("head")[0].appendChild(ss);
14072    },
14073    
14074    /**
14075     * Refresh the rule cache if you have dynamically added stylesheets
14076     * @return {Object} An object (hash) of rules indexed by selector
14077     */
14078    refreshCache : function(){
14079        return this.getRules(true);
14080    },
14081
14082    // private
14083    cacheStyleSheet : function(stylesheet){
14084        if(!rules){
14085            rules = {};
14086        }
14087        try{// try catch for cross domain access issue
14088            var ssRules = stylesheet.cssRules || stylesheet.rules;
14089            for(var j = ssRules.length-1; j >= 0; --j){
14090                rules[ssRules[j].selectorText] = ssRules[j];
14091            }
14092        }catch(e){}
14093    },
14094    
14095    /**
14096     * Gets all css rules for the document
14097     * @param {Boolean} refreshCache true to refresh the internal cache
14098     * @return {Object} An object (hash) of rules indexed by selector
14099     */
14100    getRules : function(refreshCache){
14101                 if(rules == null || refreshCache){
14102                         rules = {};
14103                         var ds = doc.styleSheets;
14104                         for(var i =0, len = ds.length; i < len; i++){
14105                             try{
14106                         this.cacheStyleSheet(ds[i]);
14107                     }catch(e){} 
14108                 }
14109                 }
14110                 return rules;
14111         },
14112         
14113         /**
14114     * Gets an an individual CSS rule by selector(s)
14115     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14116     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14117     * @return {CSSRule} The CSS rule or null if one is not found
14118     */
14119    getRule : function(selector, refreshCache){
14120                 var rs = this.getRules(refreshCache);
14121                 if(!(selector instanceof Array)){
14122                     return rs[selector];
14123                 }
14124                 for(var i = 0; i < selector.length; i++){
14125                         if(rs[selector[i]]){
14126                                 return rs[selector[i]];
14127                         }
14128                 }
14129                 return null;
14130         },
14131         
14132         
14133         /**
14134     * Updates a rule property
14135     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14136     * @param {String} property The css property
14137     * @param {String} value The new value for the property
14138     * @return {Boolean} true If a rule was found and updated
14139     */
14140    updateRule : function(selector, property, value){
14141                 if(!(selector instanceof Array)){
14142                         var rule = this.getRule(selector);
14143                         if(rule){
14144                                 rule.style[property.replace(camelRe, camelFn)] = value;
14145                                 return true;
14146                         }
14147                 }else{
14148                         for(var i = 0; i < selector.length; i++){
14149                                 if(this.updateRule(selector[i], property, value)){
14150                                         return true;
14151                                 }
14152                         }
14153                 }
14154                 return false;
14155         }
14156    };   
14157 }();/*
14158  * Based on:
14159  * Ext JS Library 1.1.1
14160  * Copyright(c) 2006-2007, Ext JS, LLC.
14161  *
14162  * Originally Released Under LGPL - original licence link has changed is not relivant.
14163  *
14164  * Fork - LGPL
14165  * <script type="text/javascript">
14166  */
14167
14168  
14169
14170 /**
14171  * @class Roo.util.ClickRepeater
14172  * @extends Roo.util.Observable
14173  * 
14174  * A wrapper class which can be applied to any element. Fires a "click" event while the
14175  * mouse is pressed. The interval between firings may be specified in the config but
14176  * defaults to 10 milliseconds.
14177  * 
14178  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14179  * 
14180  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14181  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14182  * Similar to an autorepeat key delay.
14183  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14184  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14185  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14186  *           "interval" and "delay" are ignored. "immediate" is honored.
14187  * @cfg {Boolean} preventDefault True to prevent the default click event
14188  * @cfg {Boolean} stopDefault True to stop the default click event
14189  * 
14190  * @history
14191  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14192  *     2007-02-02 jvs Renamed to ClickRepeater
14193  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14194  *
14195  *  @constructor
14196  * @param {String/HTMLElement/Element} el The element to listen on
14197  * @param {Object} config
14198  **/
14199 Roo.util.ClickRepeater = function(el, config)
14200 {
14201     this.el = Roo.get(el);
14202     this.el.unselectable();
14203
14204     Roo.apply(this, config);
14205
14206     this.addEvents({
14207     /**
14208      * @event mousedown
14209      * Fires when the mouse button is depressed.
14210      * @param {Roo.util.ClickRepeater} this
14211      */
14212         "mousedown" : true,
14213     /**
14214      * @event click
14215      * Fires on a specified interval during the time the element is pressed.
14216      * @param {Roo.util.ClickRepeater} this
14217      */
14218         "click" : true,
14219     /**
14220      * @event mouseup
14221      * Fires when the mouse key is released.
14222      * @param {Roo.util.ClickRepeater} this
14223      */
14224         "mouseup" : true
14225     });
14226
14227     this.el.on("mousedown", this.handleMouseDown, this);
14228     if(this.preventDefault || this.stopDefault){
14229         this.el.on("click", function(e){
14230             if(this.preventDefault){
14231                 e.preventDefault();
14232             }
14233             if(this.stopDefault){
14234                 e.stopEvent();
14235             }
14236         }, this);
14237     }
14238
14239     // allow inline handler
14240     if(this.handler){
14241         this.on("click", this.handler,  this.scope || this);
14242     }
14243
14244     Roo.util.ClickRepeater.superclass.constructor.call(this);
14245 };
14246
14247 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14248     interval : 20,
14249     delay: 250,
14250     preventDefault : true,
14251     stopDefault : false,
14252     timer : 0,
14253
14254     // private
14255     handleMouseDown : function(){
14256         clearTimeout(this.timer);
14257         this.el.blur();
14258         if(this.pressClass){
14259             this.el.addClass(this.pressClass);
14260         }
14261         this.mousedownTime = new Date();
14262
14263         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14264         this.el.on("mouseout", this.handleMouseOut, this);
14265
14266         this.fireEvent("mousedown", this);
14267         this.fireEvent("click", this);
14268         
14269         this.timer = this.click.defer(this.delay || this.interval, this);
14270     },
14271
14272     // private
14273     click : function(){
14274         this.fireEvent("click", this);
14275         this.timer = this.click.defer(this.getInterval(), this);
14276     },
14277
14278     // private
14279     getInterval: function(){
14280         if(!this.accelerate){
14281             return this.interval;
14282         }
14283         var pressTime = this.mousedownTime.getElapsed();
14284         if(pressTime < 500){
14285             return 400;
14286         }else if(pressTime < 1700){
14287             return 320;
14288         }else if(pressTime < 2600){
14289             return 250;
14290         }else if(pressTime < 3500){
14291             return 180;
14292         }else if(pressTime < 4400){
14293             return 140;
14294         }else if(pressTime < 5300){
14295             return 80;
14296         }else if(pressTime < 6200){
14297             return 50;
14298         }else{
14299             return 10;
14300         }
14301     },
14302
14303     // private
14304     handleMouseOut : function(){
14305         clearTimeout(this.timer);
14306         if(this.pressClass){
14307             this.el.removeClass(this.pressClass);
14308         }
14309         this.el.on("mouseover", this.handleMouseReturn, this);
14310     },
14311
14312     // private
14313     handleMouseReturn : function(){
14314         this.el.un("mouseover", this.handleMouseReturn);
14315         if(this.pressClass){
14316             this.el.addClass(this.pressClass);
14317         }
14318         this.click();
14319     },
14320
14321     // private
14322     handleMouseUp : function(){
14323         clearTimeout(this.timer);
14324         this.el.un("mouseover", this.handleMouseReturn);
14325         this.el.un("mouseout", this.handleMouseOut);
14326         Roo.get(document).un("mouseup", this.handleMouseUp);
14327         this.el.removeClass(this.pressClass);
14328         this.fireEvent("mouseup", this);
14329     }
14330 });/*
14331  * Based on:
14332  * Ext JS Library 1.1.1
14333  * Copyright(c) 2006-2007, Ext JS, LLC.
14334  *
14335  * Originally Released Under LGPL - original licence link has changed is not relivant.
14336  *
14337  * Fork - LGPL
14338  * <script type="text/javascript">
14339  */
14340
14341  
14342 /**
14343  * @class Roo.KeyNav
14344  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14345  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14346  * way to implement custom navigation schemes for any UI component.</p>
14347  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14348  * pageUp, pageDown, del, home, end.  Usage:</p>
14349  <pre><code>
14350 var nav = new Roo.KeyNav("my-element", {
14351     "left" : function(e){
14352         this.moveLeft(e.ctrlKey);
14353     },
14354     "right" : function(e){
14355         this.moveRight(e.ctrlKey);
14356     },
14357     "enter" : function(e){
14358         this.save();
14359     },
14360     scope : this
14361 });
14362 </code></pre>
14363  * @constructor
14364  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14365  * @param {Object} config The config
14366  */
14367 Roo.KeyNav = function(el, config){
14368     this.el = Roo.get(el);
14369     Roo.apply(this, config);
14370     if(!this.disabled){
14371         this.disabled = true;
14372         this.enable();
14373     }
14374 };
14375
14376 Roo.KeyNav.prototype = {
14377     /**
14378      * @cfg {Boolean} disabled
14379      * True to disable this KeyNav instance (defaults to false)
14380      */
14381     disabled : false,
14382     /**
14383      * @cfg {String} defaultEventAction
14384      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14385      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14386      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14387      */
14388     defaultEventAction: "stopEvent",
14389     /**
14390      * @cfg {Boolean} forceKeyDown
14391      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14392      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14393      * handle keydown instead of keypress.
14394      */
14395     forceKeyDown : false,
14396
14397     // private
14398     prepareEvent : function(e){
14399         var k = e.getKey();
14400         var h = this.keyToHandler[k];
14401         //if(h && this[h]){
14402         //    e.stopPropagation();
14403         //}
14404         if(Roo.isSafari && h && k >= 37 && k <= 40){
14405             e.stopEvent();
14406         }
14407     },
14408
14409     // private
14410     relay : function(e){
14411         var k = e.getKey();
14412         var h = this.keyToHandler[k];
14413         if(h && this[h]){
14414             if(this.doRelay(e, this[h], h) !== true){
14415                 e[this.defaultEventAction]();
14416             }
14417         }
14418     },
14419
14420     // private
14421     doRelay : function(e, h, hname){
14422         return h.call(this.scope || this, e);
14423     },
14424
14425     // possible handlers
14426     enter : false,
14427     left : false,
14428     right : false,
14429     up : false,
14430     down : false,
14431     tab : false,
14432     esc : false,
14433     pageUp : false,
14434     pageDown : false,
14435     del : false,
14436     home : false,
14437     end : false,
14438
14439     // quick lookup hash
14440     keyToHandler : {
14441         37 : "left",
14442         39 : "right",
14443         38 : "up",
14444         40 : "down",
14445         33 : "pageUp",
14446         34 : "pageDown",
14447         46 : "del",
14448         36 : "home",
14449         35 : "end",
14450         13 : "enter",
14451         27 : "esc",
14452         9  : "tab"
14453     },
14454
14455         /**
14456          * Enable this KeyNav
14457          */
14458         enable: function(){
14459                 if(this.disabled){
14460             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14461             // the EventObject will normalize Safari automatically
14462             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14463                 this.el.on("keydown", this.relay,  this);
14464             }else{
14465                 this.el.on("keydown", this.prepareEvent,  this);
14466                 this.el.on("keypress", this.relay,  this);
14467             }
14468                     this.disabled = false;
14469                 }
14470         },
14471
14472         /**
14473          * Disable this KeyNav
14474          */
14475         disable: function(){
14476                 if(!this.disabled){
14477                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14478                 this.el.un("keydown", this.relay);
14479             }else{
14480                 this.el.un("keydown", this.prepareEvent);
14481                 this.el.un("keypress", this.relay);
14482             }
14483                     this.disabled = true;
14484                 }
14485         }
14486 };/*
14487  * Based on:
14488  * Ext JS Library 1.1.1
14489  * Copyright(c) 2006-2007, Ext JS, LLC.
14490  *
14491  * Originally Released Under LGPL - original licence link has changed is not relivant.
14492  *
14493  * Fork - LGPL
14494  * <script type="text/javascript">
14495  */
14496
14497  
14498 /**
14499  * @class Roo.KeyMap
14500  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14501  * The constructor accepts the same config object as defined by {@link #addBinding}.
14502  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14503  * combination it will call the function with this signature (if the match is a multi-key
14504  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14505  * A KeyMap can also handle a string representation of keys.<br />
14506  * Usage:
14507  <pre><code>
14508 // map one key by key code
14509 var map = new Roo.KeyMap("my-element", {
14510     key: 13, // or Roo.EventObject.ENTER
14511     fn: myHandler,
14512     scope: myObject
14513 });
14514
14515 // map multiple keys to one action by string
14516 var map = new Roo.KeyMap("my-element", {
14517     key: "a\r\n\t",
14518     fn: myHandler,
14519     scope: myObject
14520 });
14521
14522 // map multiple keys to multiple actions by strings and array of codes
14523 var map = new Roo.KeyMap("my-element", [
14524     {
14525         key: [10,13],
14526         fn: function(){ alert("Return was pressed"); }
14527     }, {
14528         key: "abc",
14529         fn: function(){ alert('a, b or c was pressed'); }
14530     }, {
14531         key: "\t",
14532         ctrl:true,
14533         shift:true,
14534         fn: function(){ alert('Control + shift + tab was pressed.'); }
14535     }
14536 ]);
14537 </code></pre>
14538  * <b>Note: A KeyMap starts enabled</b>
14539  * @constructor
14540  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14541  * @param {Object} config The config (see {@link #addBinding})
14542  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14543  */
14544 Roo.KeyMap = function(el, config, eventName){
14545     this.el  = Roo.get(el);
14546     this.eventName = eventName || "keydown";
14547     this.bindings = [];
14548     if(config){
14549         this.addBinding(config);
14550     }
14551     this.enable();
14552 };
14553
14554 Roo.KeyMap.prototype = {
14555     /**
14556      * True to stop the event from bubbling and prevent the default browser action if the
14557      * key was handled by the KeyMap (defaults to false)
14558      * @type Boolean
14559      */
14560     stopEvent : false,
14561
14562     /**
14563      * Add a new binding to this KeyMap. The following config object properties are supported:
14564      * <pre>
14565 Property    Type             Description
14566 ----------  ---------------  ----------------------------------------------------------------------
14567 key         String/Array     A single keycode or an array of keycodes to handle
14568 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14569 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14570 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14571 fn          Function         The function to call when KeyMap finds the expected key combination
14572 scope       Object           The scope of the callback function
14573 </pre>
14574      *
14575      * Usage:
14576      * <pre><code>
14577 // Create a KeyMap
14578 var map = new Roo.KeyMap(document, {
14579     key: Roo.EventObject.ENTER,
14580     fn: handleKey,
14581     scope: this
14582 });
14583
14584 //Add a new binding to the existing KeyMap later
14585 map.addBinding({
14586     key: 'abc',
14587     shift: true,
14588     fn: handleKey,
14589     scope: this
14590 });
14591 </code></pre>
14592      * @param {Object/Array} config A single KeyMap config or an array of configs
14593      */
14594         addBinding : function(config){
14595         if(config instanceof Array){
14596             for(var i = 0, len = config.length; i < len; i++){
14597                 this.addBinding(config[i]);
14598             }
14599             return;
14600         }
14601         var keyCode = config.key,
14602             shift = config.shift, 
14603             ctrl = config.ctrl, 
14604             alt = config.alt,
14605             fn = config.fn,
14606             scope = config.scope;
14607         if(typeof keyCode == "string"){
14608             var ks = [];
14609             var keyString = keyCode.toUpperCase();
14610             for(var j = 0, len = keyString.length; j < len; j++){
14611                 ks.push(keyString.charCodeAt(j));
14612             }
14613             keyCode = ks;
14614         }
14615         var keyArray = keyCode instanceof Array;
14616         var handler = function(e){
14617             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14618                 var k = e.getKey();
14619                 if(keyArray){
14620                     for(var i = 0, len = keyCode.length; i < len; i++){
14621                         if(keyCode[i] == k){
14622                           if(this.stopEvent){
14623                               e.stopEvent();
14624                           }
14625                           fn.call(scope || window, k, e);
14626                           return;
14627                         }
14628                     }
14629                 }else{
14630                     if(k == keyCode){
14631                         if(this.stopEvent){
14632                            e.stopEvent();
14633                         }
14634                         fn.call(scope || window, k, e);
14635                     }
14636                 }
14637             }
14638         };
14639         this.bindings.push(handler);  
14640         },
14641
14642     /**
14643      * Shorthand for adding a single key listener
14644      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14645      * following options:
14646      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14647      * @param {Function} fn The function to call
14648      * @param {Object} scope (optional) The scope of the function
14649      */
14650     on : function(key, fn, scope){
14651         var keyCode, shift, ctrl, alt;
14652         if(typeof key == "object" && !(key instanceof Array)){
14653             keyCode = key.key;
14654             shift = key.shift;
14655             ctrl = key.ctrl;
14656             alt = key.alt;
14657         }else{
14658             keyCode = key;
14659         }
14660         this.addBinding({
14661             key: keyCode,
14662             shift: shift,
14663             ctrl: ctrl,
14664             alt: alt,
14665             fn: fn,
14666             scope: scope
14667         })
14668     },
14669
14670     // private
14671     handleKeyDown : function(e){
14672             if(this.enabled){ //just in case
14673             var b = this.bindings;
14674             for(var i = 0, len = b.length; i < len; i++){
14675                 b[i].call(this, e);
14676             }
14677             }
14678         },
14679         
14680         /**
14681          * Returns true if this KeyMap is enabled
14682          * @return {Boolean} 
14683          */
14684         isEnabled : function(){
14685             return this.enabled;  
14686         },
14687         
14688         /**
14689          * Enables this KeyMap
14690          */
14691         enable: function(){
14692                 if(!this.enabled){
14693                     this.el.on(this.eventName, this.handleKeyDown, this);
14694                     this.enabled = true;
14695                 }
14696         },
14697
14698         /**
14699          * Disable this KeyMap
14700          */
14701         disable: function(){
14702                 if(this.enabled){
14703                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14704                     this.enabled = false;
14705                 }
14706         }
14707 };/*
14708  * Based on:
14709  * Ext JS Library 1.1.1
14710  * Copyright(c) 2006-2007, Ext JS, LLC.
14711  *
14712  * Originally Released Under LGPL - original licence link has changed is not relivant.
14713  *
14714  * Fork - LGPL
14715  * <script type="text/javascript">
14716  */
14717
14718  
14719 /**
14720  * @class Roo.util.TextMetrics
14721  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14722  * wide, in pixels, a given block of text will be.
14723  * @singleton
14724  */
14725 Roo.util.TextMetrics = function(){
14726     var shared;
14727     return {
14728         /**
14729          * Measures the size of the specified text
14730          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14731          * that can affect the size of the rendered text
14732          * @param {String} text The text to measure
14733          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14734          * in order to accurately measure the text height
14735          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14736          */
14737         measure : function(el, text, fixedWidth){
14738             if(!shared){
14739                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14740             }
14741             shared.bind(el);
14742             shared.setFixedWidth(fixedWidth || 'auto');
14743             return shared.getSize(text);
14744         },
14745
14746         /**
14747          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14748          * the overhead of multiple calls to initialize the style properties on each measurement.
14749          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14750          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14751          * in order to accurately measure the text height
14752          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14753          */
14754         createInstance : function(el, fixedWidth){
14755             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14756         }
14757     };
14758 }();
14759
14760  
14761
14762 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14763     var ml = new Roo.Element(document.createElement('div'));
14764     document.body.appendChild(ml.dom);
14765     ml.position('absolute');
14766     ml.setLeftTop(-1000, -1000);
14767     ml.hide();
14768
14769     if(fixedWidth){
14770         ml.setWidth(fixedWidth);
14771     }
14772      
14773     var instance = {
14774         /**
14775          * Returns the size of the specified text based on the internal element's style and width properties
14776          * @memberOf Roo.util.TextMetrics.Instance#
14777          * @param {String} text The text to measure
14778          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14779          */
14780         getSize : function(text){
14781             ml.update(text);
14782             var s = ml.getSize();
14783             ml.update('');
14784             return s;
14785         },
14786
14787         /**
14788          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14789          * that can affect the size of the rendered text
14790          * @memberOf Roo.util.TextMetrics.Instance#
14791          * @param {String/HTMLElement} el The element, dom node or id
14792          */
14793         bind : function(el){
14794             ml.setStyle(
14795                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14796             );
14797         },
14798
14799         /**
14800          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14801          * to set a fixed width in order to accurately measure the text height.
14802          * @memberOf Roo.util.TextMetrics.Instance#
14803          * @param {Number} width The width to set on the element
14804          */
14805         setFixedWidth : function(width){
14806             ml.setWidth(width);
14807         },
14808
14809         /**
14810          * Returns the measured width of the specified text
14811          * @memberOf Roo.util.TextMetrics.Instance#
14812          * @param {String} text The text to measure
14813          * @return {Number} width The width in pixels
14814          */
14815         getWidth : function(text){
14816             ml.dom.style.width = 'auto';
14817             return this.getSize(text).width;
14818         },
14819
14820         /**
14821          * Returns the measured height of the specified text.  For multiline text, be sure to call
14822          * {@link #setFixedWidth} if necessary.
14823          * @memberOf Roo.util.TextMetrics.Instance#
14824          * @param {String} text The text to measure
14825          * @return {Number} height The height in pixels
14826          */
14827         getHeight : function(text){
14828             return this.getSize(text).height;
14829         }
14830     };
14831
14832     instance.bind(bindTo);
14833
14834     return instance;
14835 };
14836
14837 // backwards compat
14838 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14839  * Based on:
14840  * Ext JS Library 1.1.1
14841  * Copyright(c) 2006-2007, Ext JS, LLC.
14842  *
14843  * Originally Released Under LGPL - original licence link has changed is not relivant.
14844  *
14845  * Fork - LGPL
14846  * <script type="text/javascript">
14847  */
14848
14849 /**
14850  * @class Roo.state.Provider
14851  * Abstract base class for state provider implementations. This class provides methods
14852  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14853  * Provider interface.
14854  */
14855 Roo.state.Provider = function(){
14856     /**
14857      * @event statechange
14858      * Fires when a state change occurs.
14859      * @param {Provider} this This state provider
14860      * @param {String} key The state key which was changed
14861      * @param {String} value The encoded value for the state
14862      */
14863     this.addEvents({
14864         "statechange": true
14865     });
14866     this.state = {};
14867     Roo.state.Provider.superclass.constructor.call(this);
14868 };
14869 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14870     /**
14871      * Returns the current value for a key
14872      * @param {String} name The key name
14873      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14874      * @return {Mixed} The state data
14875      */
14876     get : function(name, defaultValue){
14877         return typeof this.state[name] == "undefined" ?
14878             defaultValue : this.state[name];
14879     },
14880     
14881     /**
14882      * Clears a value from the state
14883      * @param {String} name The key name
14884      */
14885     clear : function(name){
14886         delete this.state[name];
14887         this.fireEvent("statechange", this, name, null);
14888     },
14889     
14890     /**
14891      * Sets the value for a key
14892      * @param {String} name The key name
14893      * @param {Mixed} value The value to set
14894      */
14895     set : function(name, value){
14896         this.state[name] = value;
14897         this.fireEvent("statechange", this, name, value);
14898     },
14899     
14900     /**
14901      * Decodes a string previously encoded with {@link #encodeValue}.
14902      * @param {String} value The value to decode
14903      * @return {Mixed} The decoded value
14904      */
14905     decodeValue : function(cookie){
14906         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14907         var matches = re.exec(unescape(cookie));
14908         if(!matches || !matches[1]) {
14909             return; // non state cookie
14910         }
14911         var type = matches[1];
14912         var v = matches[2];
14913         switch(type){
14914             case "n":
14915                 return parseFloat(v);
14916             case "d":
14917                 return new Date(Date.parse(v));
14918             case "b":
14919                 return (v == "1");
14920             case "a":
14921                 var all = [];
14922                 var values = v.split("^");
14923                 for(var i = 0, len = values.length; i < len; i++){
14924                     all.push(this.decodeValue(values[i]));
14925                 }
14926                 return all;
14927            case "o":
14928                 var all = {};
14929                 var values = v.split("^");
14930                 for(var i = 0, len = values.length; i < len; i++){
14931                     var kv = values[i].split("=");
14932                     all[kv[0]] = this.decodeValue(kv[1]);
14933                 }
14934                 return all;
14935            default:
14936                 return v;
14937         }
14938     },
14939     
14940     /**
14941      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14942      * @param {Mixed} value The value to encode
14943      * @return {String} The encoded value
14944      */
14945     encodeValue : function(v){
14946         var enc;
14947         if(typeof v == "number"){
14948             enc = "n:" + v;
14949         }else if(typeof v == "boolean"){
14950             enc = "b:" + (v ? "1" : "0");
14951         }else if(v instanceof Date){
14952             enc = "d:" + v.toGMTString();
14953         }else if(v instanceof Array){
14954             var flat = "";
14955             for(var i = 0, len = v.length; i < len; i++){
14956                 flat += this.encodeValue(v[i]);
14957                 if(i != len-1) {
14958                     flat += "^";
14959                 }
14960             }
14961             enc = "a:" + flat;
14962         }else if(typeof v == "object"){
14963             var flat = "";
14964             for(var key in v){
14965                 if(typeof v[key] != "function"){
14966                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14967                 }
14968             }
14969             enc = "o:" + flat.substring(0, flat.length-1);
14970         }else{
14971             enc = "s:" + v;
14972         }
14973         return escape(enc);        
14974     }
14975 });
14976
14977 /*
14978  * Based on:
14979  * Ext JS Library 1.1.1
14980  * Copyright(c) 2006-2007, Ext JS, LLC.
14981  *
14982  * Originally Released Under LGPL - original licence link has changed is not relivant.
14983  *
14984  * Fork - LGPL
14985  * <script type="text/javascript">
14986  */
14987 /**
14988  * @class Roo.state.Manager
14989  * This is the global state manager. By default all components that are "state aware" check this class
14990  * for state information if you don't pass them a custom state provider. In order for this class
14991  * to be useful, it must be initialized with a provider when your application initializes.
14992  <pre><code>
14993 // in your initialization function
14994 init : function(){
14995    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14996    ...
14997    // supposed you have a {@link Roo.BorderLayout}
14998    var layout = new Roo.BorderLayout(...);
14999    layout.restoreState();
15000    // or a {Roo.BasicDialog}
15001    var dialog = new Roo.BasicDialog(...);
15002    dialog.restoreState();
15003  </code></pre>
15004  * @singleton
15005  */
15006 Roo.state.Manager = function(){
15007     var provider = new Roo.state.Provider();
15008     
15009     return {
15010         /**
15011          * Configures the default state provider for your application
15012          * @param {Provider} stateProvider The state provider to set
15013          */
15014         setProvider : function(stateProvider){
15015             provider = stateProvider;
15016         },
15017         
15018         /**
15019          * Returns the current value for a key
15020          * @param {String} name The key name
15021          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15022          * @return {Mixed} The state data
15023          */
15024         get : function(key, defaultValue){
15025             return provider.get(key, defaultValue);
15026         },
15027         
15028         /**
15029          * Sets the value for a key
15030          * @param {String} name The key name
15031          * @param {Mixed} value The state data
15032          */
15033          set : function(key, value){
15034             provider.set(key, value);
15035         },
15036         
15037         /**
15038          * Clears a value from the state
15039          * @param {String} name The key name
15040          */
15041         clear : function(key){
15042             provider.clear(key);
15043         },
15044         
15045         /**
15046          * Gets the currently configured state provider
15047          * @return {Provider} The state provider
15048          */
15049         getProvider : function(){
15050             return provider;
15051         }
15052     };
15053 }();
15054 /*
15055  * Based on:
15056  * Ext JS Library 1.1.1
15057  * Copyright(c) 2006-2007, Ext JS, LLC.
15058  *
15059  * Originally Released Under LGPL - original licence link has changed is not relivant.
15060  *
15061  * Fork - LGPL
15062  * <script type="text/javascript">
15063  */
15064 /**
15065  * @class Roo.state.CookieProvider
15066  * @extends Roo.state.Provider
15067  * The default Provider implementation which saves state via cookies.
15068  * <br />Usage:
15069  <pre><code>
15070    var cp = new Roo.state.CookieProvider({
15071        path: "/cgi-bin/",
15072        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15073        domain: "roojs.com"
15074    })
15075    Roo.state.Manager.setProvider(cp);
15076  </code></pre>
15077  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15078  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15079  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15080  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15081  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15082  * domain the page is running on including the 'www' like 'www.roojs.com')
15083  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15084  * @constructor
15085  * Create a new CookieProvider
15086  * @param {Object} config The configuration object
15087  */
15088 Roo.state.CookieProvider = function(config){
15089     Roo.state.CookieProvider.superclass.constructor.call(this);
15090     this.path = "/";
15091     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15092     this.domain = null;
15093     this.secure = false;
15094     Roo.apply(this, config);
15095     this.state = this.readCookies();
15096 };
15097
15098 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15099     // private
15100     set : function(name, value){
15101         if(typeof value == "undefined" || value === null){
15102             this.clear(name);
15103             return;
15104         }
15105         this.setCookie(name, value);
15106         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15107     },
15108
15109     // private
15110     clear : function(name){
15111         this.clearCookie(name);
15112         Roo.state.CookieProvider.superclass.clear.call(this, name);
15113     },
15114
15115     // private
15116     readCookies : function(){
15117         var cookies = {};
15118         var c = document.cookie + ";";
15119         var re = /\s?(.*?)=(.*?);/g;
15120         var matches;
15121         while((matches = re.exec(c)) != null){
15122             var name = matches[1];
15123             var value = matches[2];
15124             if(name && name.substring(0,3) == "ys-"){
15125                 cookies[name.substr(3)] = this.decodeValue(value);
15126             }
15127         }
15128         return cookies;
15129     },
15130
15131     // private
15132     setCookie : function(name, value){
15133         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15134            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15135            ((this.path == null) ? "" : ("; path=" + this.path)) +
15136            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15137            ((this.secure == true) ? "; secure" : "");
15138     },
15139
15140     // private
15141     clearCookie : function(name){
15142         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15143            ((this.path == null) ? "" : ("; path=" + this.path)) +
15144            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15145            ((this.secure == true) ? "; secure" : "");
15146     }
15147 });/*
15148  * Based on:
15149  * Ext JS Library 1.1.1
15150  * Copyright(c) 2006-2007, Ext JS, LLC.
15151  *
15152  * Originally Released Under LGPL - original licence link has changed is not relivant.
15153  *
15154  * Fork - LGPL
15155  * <script type="text/javascript">
15156  */
15157  
15158
15159 /**
15160  * @class Roo.ComponentMgr
15161  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15162  * @singleton
15163  */
15164 Roo.ComponentMgr = function(){
15165     var all = new Roo.util.MixedCollection();
15166
15167     return {
15168         /**
15169          * Registers a component.
15170          * @param {Roo.Component} c The component
15171          */
15172         register : function(c){
15173             all.add(c);
15174         },
15175
15176         /**
15177          * Unregisters a component.
15178          * @param {Roo.Component} c The component
15179          */
15180         unregister : function(c){
15181             all.remove(c);
15182         },
15183
15184         /**
15185          * Returns a component by id
15186          * @param {String} id The component id
15187          */
15188         get : function(id){
15189             return all.get(id);
15190         },
15191
15192         /**
15193          * Registers a function that will be called when a specified component is added to ComponentMgr
15194          * @param {String} id The component id
15195          * @param {Funtction} fn The callback function
15196          * @param {Object} scope The scope of the callback
15197          */
15198         onAvailable : function(id, fn, scope){
15199             all.on("add", function(index, o){
15200                 if(o.id == id){
15201                     fn.call(scope || o, o);
15202                     all.un("add", fn, scope);
15203                 }
15204             });
15205         }
15206     };
15207 }();/*
15208  * Based on:
15209  * Ext JS Library 1.1.1
15210  * Copyright(c) 2006-2007, Ext JS, LLC.
15211  *
15212  * Originally Released Under LGPL - original licence link has changed is not relivant.
15213  *
15214  * Fork - LGPL
15215  * <script type="text/javascript">
15216  */
15217  
15218 /**
15219  * @class Roo.Component
15220  * @extends Roo.util.Observable
15221  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15222  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15223  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15224  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15225  * All visual components (widgets) that require rendering into a layout should subclass Component.
15226  * @constructor
15227  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15228  * 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
15229  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15230  */
15231 Roo.Component = function(config){
15232     config = config || {};
15233     if(config.tagName || config.dom || typeof config == "string"){ // element object
15234         config = {el: config, id: config.id || config};
15235     }
15236     this.initialConfig = config;
15237
15238     Roo.apply(this, config);
15239     this.addEvents({
15240         /**
15241          * @event disable
15242          * Fires after the component is disabled.
15243              * @param {Roo.Component} this
15244              */
15245         disable : true,
15246         /**
15247          * @event enable
15248          * Fires after the component is enabled.
15249              * @param {Roo.Component} this
15250              */
15251         enable : true,
15252         /**
15253          * @event beforeshow
15254          * Fires before the component is shown.  Return false to stop the show.
15255              * @param {Roo.Component} this
15256              */
15257         beforeshow : true,
15258         /**
15259          * @event show
15260          * Fires after the component is shown.
15261              * @param {Roo.Component} this
15262              */
15263         show : true,
15264         /**
15265          * @event beforehide
15266          * Fires before the component is hidden. Return false to stop the hide.
15267              * @param {Roo.Component} this
15268              */
15269         beforehide : true,
15270         /**
15271          * @event hide
15272          * Fires after the component is hidden.
15273              * @param {Roo.Component} this
15274              */
15275         hide : true,
15276         /**
15277          * @event beforerender
15278          * Fires before the component is rendered. Return false to stop the render.
15279              * @param {Roo.Component} this
15280              */
15281         beforerender : true,
15282         /**
15283          * @event render
15284          * Fires after the component is rendered.
15285              * @param {Roo.Component} this
15286              */
15287         render : true,
15288         /**
15289          * @event beforedestroy
15290          * Fires before the component is destroyed. Return false to stop the destroy.
15291              * @param {Roo.Component} this
15292              */
15293         beforedestroy : true,
15294         /**
15295          * @event destroy
15296          * Fires after the component is destroyed.
15297              * @param {Roo.Component} this
15298              */
15299         destroy : true
15300     });
15301     if(!this.id){
15302         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15303     }
15304     Roo.ComponentMgr.register(this);
15305     Roo.Component.superclass.constructor.call(this);
15306     this.initComponent();
15307     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15308         this.render(this.renderTo);
15309         delete this.renderTo;
15310     }
15311 };
15312
15313 /** @private */
15314 Roo.Component.AUTO_ID = 1000;
15315
15316 Roo.extend(Roo.Component, Roo.util.Observable, {
15317     /**
15318      * @scope Roo.Component.prototype
15319      * @type {Boolean}
15320      * true if this component is hidden. Read-only.
15321      */
15322     hidden : false,
15323     /**
15324      * @type {Boolean}
15325      * true if this component is disabled. Read-only.
15326      */
15327     disabled : false,
15328     /**
15329      * @type {Boolean}
15330      * true if this component has been rendered. Read-only.
15331      */
15332     rendered : false,
15333     
15334     /** @cfg {String} disableClass
15335      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15336      */
15337     disabledClass : "x-item-disabled",
15338         /** @cfg {Boolean} allowDomMove
15339          * Whether the component can move the Dom node when rendering (defaults to true).
15340          */
15341     allowDomMove : true,
15342     /** @cfg {String} hideMode (display|visibility)
15343      * How this component should hidden. Supported values are
15344      * "visibility" (css visibility), "offsets" (negative offset position) and
15345      * "display" (css display) - defaults to "display".
15346      */
15347     hideMode: 'display',
15348
15349     /** @private */
15350     ctype : "Roo.Component",
15351
15352     /**
15353      * @cfg {String} actionMode 
15354      * which property holds the element that used for  hide() / show() / disable() / enable()
15355      * default is 'el' 
15356      */
15357     actionMode : "el",
15358
15359     /** @private */
15360     getActionEl : function(){
15361         return this[this.actionMode];
15362     },
15363
15364     initComponent : Roo.emptyFn,
15365     /**
15366      * If this is a lazy rendering component, render it to its container element.
15367      * @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.
15368      */
15369     render : function(container, position){
15370         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15371             if(!container && this.el){
15372                 this.el = Roo.get(this.el);
15373                 container = this.el.dom.parentNode;
15374                 this.allowDomMove = false;
15375             }
15376             this.container = Roo.get(container);
15377             this.rendered = true;
15378             if(position !== undefined){
15379                 if(typeof position == 'number'){
15380                     position = this.container.dom.childNodes[position];
15381                 }else{
15382                     position = Roo.getDom(position);
15383                 }
15384             }
15385             this.onRender(this.container, position || null);
15386             if(this.cls){
15387                 this.el.addClass(this.cls);
15388                 delete this.cls;
15389             }
15390             if(this.style){
15391                 this.el.applyStyles(this.style);
15392                 delete this.style;
15393             }
15394             this.fireEvent("render", this);
15395             this.afterRender(this.container);
15396             if(this.hidden){
15397                 this.hide();
15398             }
15399             if(this.disabled){
15400                 this.disable();
15401             }
15402         }
15403         return this;
15404     },
15405
15406     /** @private */
15407     // default function is not really useful
15408     onRender : function(ct, position){
15409         if(this.el){
15410             this.el = Roo.get(this.el);
15411             if(this.allowDomMove !== false){
15412                 ct.dom.insertBefore(this.el.dom, position);
15413             }
15414         }
15415     },
15416
15417     /** @private */
15418     getAutoCreate : function(){
15419         var cfg = typeof this.autoCreate == "object" ?
15420                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15421         if(this.id && !cfg.id){
15422             cfg.id = this.id;
15423         }
15424         return cfg;
15425     },
15426
15427     /** @private */
15428     afterRender : Roo.emptyFn,
15429
15430     /**
15431      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15432      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15433      */
15434     destroy : function(){
15435         if(this.fireEvent("beforedestroy", this) !== false){
15436             this.purgeListeners();
15437             this.beforeDestroy();
15438             if(this.rendered){
15439                 this.el.removeAllListeners();
15440                 this.el.remove();
15441                 if(this.actionMode == "container"){
15442                     this.container.remove();
15443                 }
15444             }
15445             this.onDestroy();
15446             Roo.ComponentMgr.unregister(this);
15447             this.fireEvent("destroy", this);
15448         }
15449     },
15450
15451         /** @private */
15452     beforeDestroy : function(){
15453
15454     },
15455
15456         /** @private */
15457         onDestroy : function(){
15458
15459     },
15460
15461     /**
15462      * Returns the underlying {@link Roo.Element}.
15463      * @return {Roo.Element} The element
15464      */
15465     getEl : function(){
15466         return this.el;
15467     },
15468
15469     /**
15470      * Returns the id of this component.
15471      * @return {String}
15472      */
15473     getId : function(){
15474         return this.id;
15475     },
15476
15477     /**
15478      * Try to focus this component.
15479      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15480      * @return {Roo.Component} this
15481      */
15482     focus : function(selectText){
15483         if(this.rendered){
15484             this.el.focus();
15485             if(selectText === true){
15486                 this.el.dom.select();
15487             }
15488         }
15489         return this;
15490     },
15491
15492     /** @private */
15493     blur : function(){
15494         if(this.rendered){
15495             this.el.blur();
15496         }
15497         return this;
15498     },
15499
15500     /**
15501      * Disable this component.
15502      * @return {Roo.Component} this
15503      */
15504     disable : function(){
15505         if(this.rendered){
15506             this.onDisable();
15507         }
15508         this.disabled = true;
15509         this.fireEvent("disable", this);
15510         return this;
15511     },
15512
15513         // private
15514     onDisable : function(){
15515         this.getActionEl().addClass(this.disabledClass);
15516         this.el.dom.disabled = true;
15517     },
15518
15519     /**
15520      * Enable this component.
15521      * @return {Roo.Component} this
15522      */
15523     enable : function(){
15524         if(this.rendered){
15525             this.onEnable();
15526         }
15527         this.disabled = false;
15528         this.fireEvent("enable", this);
15529         return this;
15530     },
15531
15532         // private
15533     onEnable : function(){
15534         this.getActionEl().removeClass(this.disabledClass);
15535         this.el.dom.disabled = false;
15536     },
15537
15538     /**
15539      * Convenience function for setting disabled/enabled by boolean.
15540      * @param {Boolean} disabled
15541      */
15542     setDisabled : function(disabled){
15543         this[disabled ? "disable" : "enable"]();
15544     },
15545
15546     /**
15547      * Show this component.
15548      * @return {Roo.Component} this
15549      */
15550     show: function(){
15551         if(this.fireEvent("beforeshow", this) !== false){
15552             this.hidden = false;
15553             if(this.rendered){
15554                 this.onShow();
15555             }
15556             this.fireEvent("show", this);
15557         }
15558         return this;
15559     },
15560
15561     // private
15562     onShow : function(){
15563         var ae = this.getActionEl();
15564         if(this.hideMode == 'visibility'){
15565             ae.dom.style.visibility = "visible";
15566         }else if(this.hideMode == 'offsets'){
15567             ae.removeClass('x-hidden');
15568         }else{
15569             ae.dom.style.display = "";
15570         }
15571     },
15572
15573     /**
15574      * Hide this component.
15575      * @return {Roo.Component} this
15576      */
15577     hide: function(){
15578         if(this.fireEvent("beforehide", this) !== false){
15579             this.hidden = true;
15580             if(this.rendered){
15581                 this.onHide();
15582             }
15583             this.fireEvent("hide", this);
15584         }
15585         return this;
15586     },
15587
15588     // private
15589     onHide : function(){
15590         var ae = this.getActionEl();
15591         if(this.hideMode == 'visibility'){
15592             ae.dom.style.visibility = "hidden";
15593         }else if(this.hideMode == 'offsets'){
15594             ae.addClass('x-hidden');
15595         }else{
15596             ae.dom.style.display = "none";
15597         }
15598     },
15599
15600     /**
15601      * Convenience function to hide or show this component by boolean.
15602      * @param {Boolean} visible True to show, false to hide
15603      * @return {Roo.Component} this
15604      */
15605     setVisible: function(visible){
15606         if(visible) {
15607             this.show();
15608         }else{
15609             this.hide();
15610         }
15611         return this;
15612     },
15613
15614     /**
15615      * Returns true if this component is visible.
15616      */
15617     isVisible : function(){
15618         return this.getActionEl().isVisible();
15619     },
15620
15621     cloneConfig : function(overrides){
15622         overrides = overrides || {};
15623         var id = overrides.id || Roo.id();
15624         var cfg = Roo.applyIf(overrides, this.initialConfig);
15625         cfg.id = id; // prevent dup id
15626         return new this.constructor(cfg);
15627     }
15628 });/*
15629  * Based on:
15630  * Ext JS Library 1.1.1
15631  * Copyright(c) 2006-2007, Ext JS, LLC.
15632  *
15633  * Originally Released Under LGPL - original licence link has changed is not relivant.
15634  *
15635  * Fork - LGPL
15636  * <script type="text/javascript">
15637  */
15638
15639 /**
15640  * @class Roo.BoxComponent
15641  * @extends Roo.Component
15642  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15643  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15644  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15645  * layout containers.
15646  * @constructor
15647  * @param {Roo.Element/String/Object} config The configuration options.
15648  */
15649 Roo.BoxComponent = function(config){
15650     Roo.Component.call(this, config);
15651     this.addEvents({
15652         /**
15653          * @event resize
15654          * Fires after the component is resized.
15655              * @param {Roo.Component} this
15656              * @param {Number} adjWidth The box-adjusted width that was set
15657              * @param {Number} adjHeight The box-adjusted height that was set
15658              * @param {Number} rawWidth The width that was originally specified
15659              * @param {Number} rawHeight The height that was originally specified
15660              */
15661         resize : true,
15662         /**
15663          * @event move
15664          * Fires after the component is moved.
15665              * @param {Roo.Component} this
15666              * @param {Number} x The new x position
15667              * @param {Number} y The new y position
15668              */
15669         move : true
15670     });
15671 };
15672
15673 Roo.extend(Roo.BoxComponent, Roo.Component, {
15674     // private, set in afterRender to signify that the component has been rendered
15675     boxReady : false,
15676     // private, used to defer height settings to subclasses
15677     deferHeight: false,
15678     /** @cfg {Number} width
15679      * width (optional) size of component
15680      */
15681      /** @cfg {Number} height
15682      * height (optional) size of component
15683      */
15684      
15685     /**
15686      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15687      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15688      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15689      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15690      * @return {Roo.BoxComponent} this
15691      */
15692     setSize : function(w, h){
15693         // support for standard size objects
15694         if(typeof w == 'object'){
15695             h = w.height;
15696             w = w.width;
15697         }
15698         // not rendered
15699         if(!this.boxReady){
15700             this.width = w;
15701             this.height = h;
15702             return this;
15703         }
15704
15705         // prevent recalcs when not needed
15706         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15707             return this;
15708         }
15709         this.lastSize = {width: w, height: h};
15710
15711         var adj = this.adjustSize(w, h);
15712         var aw = adj.width, ah = adj.height;
15713         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15714             var rz = this.getResizeEl();
15715             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15716                 rz.setSize(aw, ah);
15717             }else if(!this.deferHeight && ah !== undefined){
15718                 rz.setHeight(ah);
15719             }else if(aw !== undefined){
15720                 rz.setWidth(aw);
15721             }
15722             this.onResize(aw, ah, w, h);
15723             this.fireEvent('resize', this, aw, ah, w, h);
15724         }
15725         return this;
15726     },
15727
15728     /**
15729      * Gets the current size of the component's underlying element.
15730      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15731      */
15732     getSize : function(){
15733         return this.el.getSize();
15734     },
15735
15736     /**
15737      * Gets the current XY position of the component's underlying element.
15738      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15739      * @return {Array} The XY position of the element (e.g., [100, 200])
15740      */
15741     getPosition : function(local){
15742         if(local === true){
15743             return [this.el.getLeft(true), this.el.getTop(true)];
15744         }
15745         return this.xy || this.el.getXY();
15746     },
15747
15748     /**
15749      * Gets the current box measurements of the component's underlying element.
15750      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15751      * @returns {Object} box An object in the format {x, y, width, height}
15752      */
15753     getBox : function(local){
15754         var s = this.el.getSize();
15755         if(local){
15756             s.x = this.el.getLeft(true);
15757             s.y = this.el.getTop(true);
15758         }else{
15759             var xy = this.xy || this.el.getXY();
15760             s.x = xy[0];
15761             s.y = xy[1];
15762         }
15763         return s;
15764     },
15765
15766     /**
15767      * Sets the current box measurements of the component's underlying element.
15768      * @param {Object} box An object in the format {x, y, width, height}
15769      * @returns {Roo.BoxComponent} this
15770      */
15771     updateBox : function(box){
15772         this.setSize(box.width, box.height);
15773         this.setPagePosition(box.x, box.y);
15774         return this;
15775     },
15776
15777     // protected
15778     getResizeEl : function(){
15779         return this.resizeEl || this.el;
15780     },
15781
15782     // protected
15783     getPositionEl : function(){
15784         return this.positionEl || this.el;
15785     },
15786
15787     /**
15788      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15789      * This method fires the move event.
15790      * @param {Number} left The new left
15791      * @param {Number} top The new top
15792      * @returns {Roo.BoxComponent} this
15793      */
15794     setPosition : function(x, y){
15795         this.x = x;
15796         this.y = y;
15797         if(!this.boxReady){
15798             return this;
15799         }
15800         var adj = this.adjustPosition(x, y);
15801         var ax = adj.x, ay = adj.y;
15802
15803         var el = this.getPositionEl();
15804         if(ax !== undefined || ay !== undefined){
15805             if(ax !== undefined && ay !== undefined){
15806                 el.setLeftTop(ax, ay);
15807             }else if(ax !== undefined){
15808                 el.setLeft(ax);
15809             }else if(ay !== undefined){
15810                 el.setTop(ay);
15811             }
15812             this.onPosition(ax, ay);
15813             this.fireEvent('move', this, ax, ay);
15814         }
15815         return this;
15816     },
15817
15818     /**
15819      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15820      * This method fires the move event.
15821      * @param {Number} x The new x position
15822      * @param {Number} y The new y position
15823      * @returns {Roo.BoxComponent} this
15824      */
15825     setPagePosition : function(x, y){
15826         this.pageX = x;
15827         this.pageY = y;
15828         if(!this.boxReady){
15829             return;
15830         }
15831         if(x === undefined || y === undefined){ // cannot translate undefined points
15832             return;
15833         }
15834         var p = this.el.translatePoints(x, y);
15835         this.setPosition(p.left, p.top);
15836         return this;
15837     },
15838
15839     // private
15840     onRender : function(ct, position){
15841         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15842         if(this.resizeEl){
15843             this.resizeEl = Roo.get(this.resizeEl);
15844         }
15845         if(this.positionEl){
15846             this.positionEl = Roo.get(this.positionEl);
15847         }
15848     },
15849
15850     // private
15851     afterRender : function(){
15852         Roo.BoxComponent.superclass.afterRender.call(this);
15853         this.boxReady = true;
15854         this.setSize(this.width, this.height);
15855         if(this.x || this.y){
15856             this.setPosition(this.x, this.y);
15857         }
15858         if(this.pageX || this.pageY){
15859             this.setPagePosition(this.pageX, this.pageY);
15860         }
15861     },
15862
15863     /**
15864      * Force the component's size to recalculate based on the underlying element's current height and width.
15865      * @returns {Roo.BoxComponent} this
15866      */
15867     syncSize : function(){
15868         delete this.lastSize;
15869         this.setSize(this.el.getWidth(), this.el.getHeight());
15870         return this;
15871     },
15872
15873     /**
15874      * Called after the component is resized, this method is empty by default but can be implemented by any
15875      * subclass that needs to perform custom logic after a resize occurs.
15876      * @param {Number} adjWidth The box-adjusted width that was set
15877      * @param {Number} adjHeight The box-adjusted height that was set
15878      * @param {Number} rawWidth The width that was originally specified
15879      * @param {Number} rawHeight The height that was originally specified
15880      */
15881     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15882
15883     },
15884
15885     /**
15886      * Called after the component is moved, this method is empty by default but can be implemented by any
15887      * subclass that needs to perform custom logic after a move occurs.
15888      * @param {Number} x The new x position
15889      * @param {Number} y The new y position
15890      */
15891     onPosition : function(x, y){
15892
15893     },
15894
15895     // private
15896     adjustSize : function(w, h){
15897         if(this.autoWidth){
15898             w = 'auto';
15899         }
15900         if(this.autoHeight){
15901             h = 'auto';
15902         }
15903         return {width : w, height: h};
15904     },
15905
15906     // private
15907     adjustPosition : function(x, y){
15908         return {x : x, y: y};
15909     }
15910 });/*
15911  * Original code for Roojs - LGPL
15912  * <script type="text/javascript">
15913  */
15914  
15915 /**
15916  * @class Roo.XComponent
15917  * A delayed Element creator...
15918  * Or a way to group chunks of interface together.
15919  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15920  *  used in conjunction with XComponent.build() it will create an instance of each element,
15921  *  then call addxtype() to build the User interface.
15922  * 
15923  * Mypart.xyx = new Roo.XComponent({
15924
15925     parent : 'Mypart.xyz', // empty == document.element.!!
15926     order : '001',
15927     name : 'xxxx'
15928     region : 'xxxx'
15929     disabled : function() {} 
15930      
15931     tree : function() { // return an tree of xtype declared components
15932         var MODULE = this;
15933         return 
15934         {
15935             xtype : 'NestedLayoutPanel',
15936             // technicall
15937         }
15938      ]
15939  *})
15940  *
15941  *
15942  * It can be used to build a big heiracy, with parent etc.
15943  * or you can just use this to render a single compoent to a dom element
15944  * MYPART.render(Roo.Element | String(id) | dom_element )
15945  *
15946  *
15947  * Usage patterns.
15948  *
15949  * Classic Roo
15950  *
15951  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15952  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15953  *
15954  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15955  *
15956  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15957  * - if mulitple topModules exist, the last one is defined as the top module.
15958  *
15959  * Embeded Roo
15960  * 
15961  * When the top level or multiple modules are to embedded into a existing HTML page,
15962  * the parent element can container '#id' of the element where the module will be drawn.
15963  *
15964  * Bootstrap Roo
15965  *
15966  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15967  * it relies more on a include mechanism, where sub modules are included into an outer page.
15968  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15969  * 
15970  * Bootstrap Roo Included elements
15971  *
15972  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15973  * hence confusing the component builder as it thinks there are multiple top level elements. 
15974  *
15975  * 
15976  * 
15977  * @extends Roo.util.Observable
15978  * @constructor
15979  * @param cfg {Object} configuration of component
15980  * 
15981  */
15982 Roo.XComponent = function(cfg) {
15983     Roo.apply(this, cfg);
15984     this.addEvents({ 
15985         /**
15986              * @event built
15987              * Fires when this the componnt is built
15988              * @param {Roo.XComponent} c the component
15989              */
15990         'built' : true
15991         
15992     });
15993     this.region = this.region || 'center'; // default..
15994     Roo.XComponent.register(this);
15995     this.modules = false;
15996     this.el = false; // where the layout goes..
15997     
15998     
15999 }
16000 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16001     /**
16002      * @property el
16003      * The created element (with Roo.factory())
16004      * @type {Roo.Layout}
16005      */
16006     el  : false,
16007     
16008     /**
16009      * @property el
16010      * for BC  - use el in new code
16011      * @type {Roo.Layout}
16012      */
16013     panel : false,
16014     
16015     /**
16016      * @property layout
16017      * for BC  - use el in new code
16018      * @type {Roo.Layout}
16019      */
16020     layout : false,
16021     
16022      /**
16023      * @cfg {Function|boolean} disabled
16024      * If this module is disabled by some rule, return true from the funtion
16025      */
16026     disabled : false,
16027     
16028     /**
16029      * @cfg {String} parent 
16030      * Name of parent element which it get xtype added to..
16031      */
16032     parent: false,
16033     
16034     /**
16035      * @cfg {String} order
16036      * Used to set the order in which elements are created (usefull for multiple tabs)
16037      */
16038     
16039     order : false,
16040     /**
16041      * @cfg {String} name
16042      * String to display while loading.
16043      */
16044     name : false,
16045     /**
16046      * @cfg {String} region
16047      * Region to render component to (defaults to center)
16048      */
16049     region : 'center',
16050     
16051     /**
16052      * @cfg {Array} items
16053      * A single item array - the first element is the root of the tree..
16054      * It's done this way to stay compatible with the Xtype system...
16055      */
16056     items : false,
16057     
16058     /**
16059      * @property _tree
16060      * The method that retuns the tree of parts that make up this compoennt 
16061      * @type {function}
16062      */
16063     _tree  : false,
16064     
16065      /**
16066      * render
16067      * render element to dom or tree
16068      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16069      */
16070     
16071     render : function(el)
16072     {
16073         
16074         el = el || false;
16075         var hp = this.parent ? 1 : 0;
16076         Roo.debug &&  Roo.log(this);
16077         
16078         var tree = this._tree ? this._tree() : this.tree();
16079
16080         
16081         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16082             // if parent is a '#.....' string, then let's use that..
16083             var ename = this.parent.substr(1);
16084             this.parent = false;
16085             Roo.debug && Roo.log(ename);
16086             switch (ename) {
16087                 case 'bootstrap-body':
16088                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16089                         // this is the BorderLayout standard?
16090                        this.parent = { el : true };
16091                        break;
16092                     }
16093                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16094                         // need to insert stuff...
16095                         this.parent =  {
16096                              el : new Roo.bootstrap.layout.Border({
16097                                  el : document.body, 
16098                      
16099                                  center: {
16100                                     titlebar: false,
16101                                     autoScroll:false,
16102                                     closeOnTab: true,
16103                                     tabPosition: 'top',
16104                                       //resizeTabs: true,
16105                                     alwaysShowTabs: true,
16106                                     hideTabs: false
16107                                      //minTabWidth: 140
16108                                  }
16109                              })
16110                         
16111                          };
16112                          break;
16113                     }
16114                          
16115                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16116                         this.parent = { el :  new  Roo.bootstrap.Body() };
16117                         Roo.debug && Roo.log("setting el to doc body");
16118                          
16119                     } else {
16120                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16121                     }
16122                     break;
16123                 case 'bootstrap':
16124                     this.parent = { el : true};
16125                     // fall through
16126                 default:
16127                     el = Roo.get(ename);
16128                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16129                         this.parent = { el : true};
16130                     }
16131                     
16132                     break;
16133             }
16134                 
16135             
16136             if (!el && !this.parent) {
16137                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16138                 return;
16139             }
16140         }
16141         
16142         Roo.debug && Roo.log("EL:");
16143         Roo.debug && Roo.log(el);
16144         Roo.debug && Roo.log("this.parent.el:");
16145         Roo.debug && Roo.log(this.parent.el);
16146         
16147
16148         // altertive root elements ??? - we need a better way to indicate these.
16149         var is_alt = Roo.XComponent.is_alt ||
16150                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16151                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16152                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16153         
16154         
16155         
16156         if (!this.parent && is_alt) {
16157             //el = Roo.get(document.body);
16158             this.parent = { el : true };
16159         }
16160             
16161             
16162         
16163         if (!this.parent) {
16164             
16165             Roo.debug && Roo.log("no parent - creating one");
16166             
16167             el = el ? Roo.get(el) : false;      
16168             
16169             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16170                 
16171                 this.parent =  {
16172                     el : new Roo.bootstrap.layout.Border({
16173                         el: el || document.body,
16174                     
16175                         center: {
16176                             titlebar: false,
16177                             autoScroll:false,
16178                             closeOnTab: true,
16179                             tabPosition: 'top',
16180                              //resizeTabs: true,
16181                             alwaysShowTabs: false,
16182                             hideTabs: true,
16183                             minTabWidth: 140,
16184                             overflow: 'visible'
16185                          }
16186                      })
16187                 };
16188             } else {
16189             
16190                 // it's a top level one..
16191                 this.parent =  {
16192                     el : new Roo.BorderLayout(el || document.body, {
16193                         center: {
16194                             titlebar: false,
16195                             autoScroll:false,
16196                             closeOnTab: true,
16197                             tabPosition: 'top',
16198                              //resizeTabs: true,
16199                             alwaysShowTabs: el && hp? false :  true,
16200                             hideTabs: el || !hp ? true :  false,
16201                             minTabWidth: 140
16202                          }
16203                     })
16204                 };
16205             }
16206         }
16207         
16208         if (!this.parent.el) {
16209                 // probably an old style ctor, which has been disabled.
16210                 return;
16211
16212         }
16213                 // The 'tree' method is  '_tree now' 
16214             
16215         tree.region = tree.region || this.region;
16216         var is_body = false;
16217         if (this.parent.el === true) {
16218             // bootstrap... - body..
16219             if (el) {
16220                 tree.el = el;
16221             }
16222             this.parent.el = Roo.factory(tree);
16223             is_body = true;
16224         }
16225         
16226         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16227         this.fireEvent('built', this);
16228         
16229         this.panel = this.el;
16230         this.layout = this.panel.layout;
16231         this.parentLayout = this.parent.layout  || false;  
16232          
16233     }
16234     
16235 });
16236
16237 Roo.apply(Roo.XComponent, {
16238     /**
16239      * @property  hideProgress
16240      * true to disable the building progress bar.. usefull on single page renders.
16241      * @type Boolean
16242      */
16243     hideProgress : false,
16244     /**
16245      * @property  buildCompleted
16246      * True when the builder has completed building the interface.
16247      * @type Boolean
16248      */
16249     buildCompleted : false,
16250      
16251     /**
16252      * @property  topModule
16253      * the upper most module - uses document.element as it's constructor.
16254      * @type Object
16255      */
16256      
16257     topModule  : false,
16258       
16259     /**
16260      * @property  modules
16261      * array of modules to be created by registration system.
16262      * @type {Array} of Roo.XComponent
16263      */
16264     
16265     modules : [],
16266     /**
16267      * @property  elmodules
16268      * array of modules to be created by which use #ID 
16269      * @type {Array} of Roo.XComponent
16270      */
16271      
16272     elmodules : [],
16273
16274      /**
16275      * @property  is_alt
16276      * Is an alternative Root - normally used by bootstrap or other systems,
16277      *    where the top element in the tree can wrap 'body' 
16278      * @type {boolean}  (default false)
16279      */
16280      
16281     is_alt : false,
16282     /**
16283      * @property  build_from_html
16284      * Build elements from html - used by bootstrap HTML stuff 
16285      *    - this is cleared after build is completed
16286      * @type {boolean}    (default false)
16287      */
16288      
16289     build_from_html : false,
16290     /**
16291      * Register components to be built later.
16292      *
16293      * This solves the following issues
16294      * - Building is not done on page load, but after an authentication process has occured.
16295      * - Interface elements are registered on page load
16296      * - Parent Interface elements may not be loaded before child, so this handles that..
16297      * 
16298      *
16299      * example:
16300      * 
16301      * MyApp.register({
16302           order : '000001',
16303           module : 'Pman.Tab.projectMgr',
16304           region : 'center',
16305           parent : 'Pman.layout',
16306           disabled : false,  // or use a function..
16307         })
16308      
16309      * * @param {Object} details about module
16310      */
16311     register : function(obj) {
16312                 
16313         Roo.XComponent.event.fireEvent('register', obj);
16314         switch(typeof(obj.disabled) ) {
16315                 
16316             case 'undefined':
16317                 break;
16318             
16319             case 'function':
16320                 if ( obj.disabled() ) {
16321                         return;
16322                 }
16323                 break;
16324             
16325             default:
16326                 if (obj.disabled) {
16327                         return;
16328                 }
16329                 break;
16330         }
16331                 
16332         this.modules.push(obj);
16333          
16334     },
16335     /**
16336      * convert a string to an object..
16337      * eg. 'AAA.BBB' -> finds AAA.BBB
16338
16339      */
16340     
16341     toObject : function(str)
16342     {
16343         if (!str || typeof(str) == 'object') {
16344             return str;
16345         }
16346         if (str.substring(0,1) == '#') {
16347             return str;
16348         }
16349
16350         var ar = str.split('.');
16351         var rt, o;
16352         rt = ar.shift();
16353             /** eval:var:o */
16354         try {
16355             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16356         } catch (e) {
16357             throw "Module not found : " + str;
16358         }
16359         
16360         if (o === false) {
16361             throw "Module not found : " + str;
16362         }
16363         Roo.each(ar, function(e) {
16364             if (typeof(o[e]) == 'undefined') {
16365                 throw "Module not found : " + str;
16366             }
16367             o = o[e];
16368         });
16369         
16370         return o;
16371         
16372     },
16373     
16374     
16375     /**
16376      * move modules into their correct place in the tree..
16377      * 
16378      */
16379     preBuild : function ()
16380     {
16381         var _t = this;
16382         Roo.each(this.modules , function (obj)
16383         {
16384             Roo.XComponent.event.fireEvent('beforebuild', obj);
16385             
16386             var opar = obj.parent;
16387             try { 
16388                 obj.parent = this.toObject(opar);
16389             } catch(e) {
16390                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16391                 return;
16392             }
16393             
16394             if (!obj.parent) {
16395                 Roo.debug && Roo.log("GOT top level module");
16396                 Roo.debug && Roo.log(obj);
16397                 obj.modules = new Roo.util.MixedCollection(false, 
16398                     function(o) { return o.order + '' }
16399                 );
16400                 this.topModule = obj;
16401                 return;
16402             }
16403                         // parent is a string (usually a dom element name..)
16404             if (typeof(obj.parent) == 'string') {
16405                 this.elmodules.push(obj);
16406                 return;
16407             }
16408             if (obj.parent.constructor != Roo.XComponent) {
16409                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16410             }
16411             if (!obj.parent.modules) {
16412                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16413                     function(o) { return o.order + '' }
16414                 );
16415             }
16416             if (obj.parent.disabled) {
16417                 obj.disabled = true;
16418             }
16419             obj.parent.modules.add(obj);
16420         }, this);
16421     },
16422     
16423      /**
16424      * make a list of modules to build.
16425      * @return {Array} list of modules. 
16426      */ 
16427     
16428     buildOrder : function()
16429     {
16430         var _this = this;
16431         var cmp = function(a,b) {   
16432             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16433         };
16434         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16435             throw "No top level modules to build";
16436         }
16437         
16438         // make a flat list in order of modules to build.
16439         var mods = this.topModule ? [ this.topModule ] : [];
16440                 
16441         
16442         // elmodules (is a list of DOM based modules )
16443         Roo.each(this.elmodules, function(e) {
16444             mods.push(e);
16445             if (!this.topModule &&
16446                 typeof(e.parent) == 'string' &&
16447                 e.parent.substring(0,1) == '#' &&
16448                 Roo.get(e.parent.substr(1))
16449                ) {
16450                 
16451                 _this.topModule = e;
16452             }
16453             
16454         });
16455
16456         
16457         // add modules to their parents..
16458         var addMod = function(m) {
16459             Roo.debug && Roo.log("build Order: add: " + m.name);
16460                 
16461             mods.push(m);
16462             if (m.modules && !m.disabled) {
16463                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16464                 m.modules.keySort('ASC',  cmp );
16465                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16466     
16467                 m.modules.each(addMod);
16468             } else {
16469                 Roo.debug && Roo.log("build Order: no child modules");
16470             }
16471             // not sure if this is used any more..
16472             if (m.finalize) {
16473                 m.finalize.name = m.name + " (clean up) ";
16474                 mods.push(m.finalize);
16475             }
16476             
16477         }
16478         if (this.topModule && this.topModule.modules) { 
16479             this.topModule.modules.keySort('ASC',  cmp );
16480             this.topModule.modules.each(addMod);
16481         } 
16482         return mods;
16483     },
16484     
16485      /**
16486      * Build the registered modules.
16487      * @param {Object} parent element.
16488      * @param {Function} optional method to call after module has been added.
16489      * 
16490      */ 
16491    
16492     build : function(opts) 
16493     {
16494         
16495         if (typeof(opts) != 'undefined') {
16496             Roo.apply(this,opts);
16497         }
16498         
16499         this.preBuild();
16500         var mods = this.buildOrder();
16501       
16502         //this.allmods = mods;
16503         //Roo.debug && Roo.log(mods);
16504         //return;
16505         if (!mods.length) { // should not happen
16506             throw "NO modules!!!";
16507         }
16508         
16509         
16510         var msg = "Building Interface...";
16511         // flash it up as modal - so we store the mask!?
16512         if (!this.hideProgress && Roo.MessageBox) {
16513             Roo.MessageBox.show({ title: 'loading' });
16514             Roo.MessageBox.show({
16515                title: "Please wait...",
16516                msg: msg,
16517                width:450,
16518                progress:true,
16519                closable:false,
16520                modal: false
16521               
16522             });
16523         }
16524         var total = mods.length;
16525         
16526         var _this = this;
16527         var progressRun = function() {
16528             if (!mods.length) {
16529                 Roo.debug && Roo.log('hide?');
16530                 if (!this.hideProgress && Roo.MessageBox) {
16531                     Roo.MessageBox.hide();
16532                 }
16533                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16534                 
16535                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16536                 
16537                 // THE END...
16538                 return false;   
16539             }
16540             
16541             var m = mods.shift();
16542             
16543             
16544             Roo.debug && Roo.log(m);
16545             // not sure if this is supported any more.. - modules that are are just function
16546             if (typeof(m) == 'function') { 
16547                 m.call(this);
16548                 return progressRun.defer(10, _this);
16549             } 
16550             
16551             
16552             msg = "Building Interface " + (total  - mods.length) + 
16553                     " of " + total + 
16554                     (m.name ? (' - ' + m.name) : '');
16555                         Roo.debug && Roo.log(msg);
16556             if (!_this.hideProgress &&  Roo.MessageBox) { 
16557                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16558             }
16559             
16560          
16561             // is the module disabled?
16562             var disabled = (typeof(m.disabled) == 'function') ?
16563                 m.disabled.call(m.module.disabled) : m.disabled;    
16564             
16565             
16566             if (disabled) {
16567                 return progressRun(); // we do not update the display!
16568             }
16569             
16570             // now build 
16571             
16572                         
16573                         
16574             m.render();
16575             // it's 10 on top level, and 1 on others??? why...
16576             return progressRun.defer(10, _this);
16577              
16578         }
16579         progressRun.defer(1, _this);
16580      
16581         
16582         
16583     },
16584         
16585         
16586         /**
16587          * Event Object.
16588          *
16589          *
16590          */
16591         event: false, 
16592     /**
16593          * wrapper for event.on - aliased later..  
16594          * Typically use to register a event handler for register:
16595          *
16596          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16597          *
16598          */
16599     on : false
16600    
16601     
16602     
16603 });
16604
16605 Roo.XComponent.event = new Roo.util.Observable({
16606                 events : { 
16607                         /**
16608                          * @event register
16609                          * Fires when an Component is registered,
16610                          * set the disable property on the Component to stop registration.
16611                          * @param {Roo.XComponent} c the component being registerd.
16612                          * 
16613                          */
16614                         'register' : true,
16615             /**
16616                          * @event beforebuild
16617                          * Fires before each Component is built
16618                          * can be used to apply permissions.
16619                          * @param {Roo.XComponent} c the component being registerd.
16620                          * 
16621                          */
16622                         'beforebuild' : true,
16623                         /**
16624                          * @event buildcomplete
16625                          * Fires on the top level element when all elements have been built
16626                          * @param {Roo.XComponent} the top level component.
16627                          */
16628                         'buildcomplete' : true
16629                         
16630                 }
16631 });
16632
16633 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16634  //
16635  /**
16636  * marked - a markdown parser
16637  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16638  * https://github.com/chjj/marked
16639  */
16640
16641
16642 /**
16643  *
16644  * Roo.Markdown - is a very crude wrapper around marked..
16645  *
16646  * usage:
16647  * 
16648  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16649  * 
16650  * Note: move the sample code to the bottom of this
16651  * file before uncommenting it.
16652  *
16653  */
16654
16655 Roo.Markdown = {};
16656 Roo.Markdown.toHtml = function(text) {
16657     
16658     var c = new Roo.Markdown.marked.setOptions({
16659             renderer: new Roo.Markdown.marked.Renderer(),
16660             gfm: true,
16661             tables: true,
16662             breaks: false,
16663             pedantic: false,
16664             sanitize: false,
16665             smartLists: true,
16666             smartypants: false
16667           });
16668     // A FEW HACKS!!?
16669     
16670     text = text.replace(/\\\n/g,' ');
16671     return Roo.Markdown.marked(text);
16672 };
16673 //
16674 // converter
16675 //
16676 // Wraps all "globals" so that the only thing
16677 // exposed is makeHtml().
16678 //
16679 (function() {
16680     
16681     /**
16682      * Block-Level Grammar
16683      */
16684     
16685     var block = {
16686       newline: /^\n+/,
16687       code: /^( {4}[^\n]+\n*)+/,
16688       fences: noop,
16689       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16690       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16691       nptable: noop,
16692       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16693       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16694       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16695       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16696       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16697       table: noop,
16698       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16699       text: /^[^\n]+/
16700     };
16701     
16702     block.bullet = /(?:[*+-]|\d+\.)/;
16703     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16704     block.item = replace(block.item, 'gm')
16705       (/bull/g, block.bullet)
16706       ();
16707     
16708     block.list = replace(block.list)
16709       (/bull/g, block.bullet)
16710       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16711       ('def', '\\n+(?=' + block.def.source + ')')
16712       ();
16713     
16714     block.blockquote = replace(block.blockquote)
16715       ('def', block.def)
16716       ();
16717     
16718     block._tag = '(?!(?:'
16719       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16720       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16721       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16722     
16723     block.html = replace(block.html)
16724       ('comment', /<!--[\s\S]*?-->/)
16725       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16726       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16727       (/tag/g, block._tag)
16728       ();
16729     
16730     block.paragraph = replace(block.paragraph)
16731       ('hr', block.hr)
16732       ('heading', block.heading)
16733       ('lheading', block.lheading)
16734       ('blockquote', block.blockquote)
16735       ('tag', '<' + block._tag)
16736       ('def', block.def)
16737       ();
16738     
16739     /**
16740      * Normal Block Grammar
16741      */
16742     
16743     block.normal = merge({}, block);
16744     
16745     /**
16746      * GFM Block Grammar
16747      */
16748     
16749     block.gfm = merge({}, block.normal, {
16750       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16751       paragraph: /^/,
16752       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16753     });
16754     
16755     block.gfm.paragraph = replace(block.paragraph)
16756       ('(?!', '(?!'
16757         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16758         + block.list.source.replace('\\1', '\\3') + '|')
16759       ();
16760     
16761     /**
16762      * GFM + Tables Block Grammar
16763      */
16764     
16765     block.tables = merge({}, block.gfm, {
16766       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16767       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16768     });
16769     
16770     /**
16771      * Block Lexer
16772      */
16773     
16774     function Lexer(options) {
16775       this.tokens = [];
16776       this.tokens.links = {};
16777       this.options = options || marked.defaults;
16778       this.rules = block.normal;
16779     
16780       if (this.options.gfm) {
16781         if (this.options.tables) {
16782           this.rules = block.tables;
16783         } else {
16784           this.rules = block.gfm;
16785         }
16786       }
16787     }
16788     
16789     /**
16790      * Expose Block Rules
16791      */
16792     
16793     Lexer.rules = block;
16794     
16795     /**
16796      * Static Lex Method
16797      */
16798     
16799     Lexer.lex = function(src, options) {
16800       var lexer = new Lexer(options);
16801       return lexer.lex(src);
16802     };
16803     
16804     /**
16805      * Preprocessing
16806      */
16807     
16808     Lexer.prototype.lex = function(src) {
16809       src = src
16810         .replace(/\r\n|\r/g, '\n')
16811         .replace(/\t/g, '    ')
16812         .replace(/\u00a0/g, ' ')
16813         .replace(/\u2424/g, '\n');
16814     
16815       return this.token(src, true);
16816     };
16817     
16818     /**
16819      * Lexing
16820      */
16821     
16822     Lexer.prototype.token = function(src, top, bq) {
16823       var src = src.replace(/^ +$/gm, '')
16824         , next
16825         , loose
16826         , cap
16827         , bull
16828         , b
16829         , item
16830         , space
16831         , i
16832         , l;
16833     
16834       while (src) {
16835         // newline
16836         if (cap = this.rules.newline.exec(src)) {
16837           src = src.substring(cap[0].length);
16838           if (cap[0].length > 1) {
16839             this.tokens.push({
16840               type: 'space'
16841             });
16842           }
16843         }
16844     
16845         // code
16846         if (cap = this.rules.code.exec(src)) {
16847           src = src.substring(cap[0].length);
16848           cap = cap[0].replace(/^ {4}/gm, '');
16849           this.tokens.push({
16850             type: 'code',
16851             text: !this.options.pedantic
16852               ? cap.replace(/\n+$/, '')
16853               : cap
16854           });
16855           continue;
16856         }
16857     
16858         // fences (gfm)
16859         if (cap = this.rules.fences.exec(src)) {
16860           src = src.substring(cap[0].length);
16861           this.tokens.push({
16862             type: 'code',
16863             lang: cap[2],
16864             text: cap[3] || ''
16865           });
16866           continue;
16867         }
16868     
16869         // heading
16870         if (cap = this.rules.heading.exec(src)) {
16871           src = src.substring(cap[0].length);
16872           this.tokens.push({
16873             type: 'heading',
16874             depth: cap[1].length,
16875             text: cap[2]
16876           });
16877           continue;
16878         }
16879     
16880         // table no leading pipe (gfm)
16881         if (top && (cap = this.rules.nptable.exec(src))) {
16882           src = src.substring(cap[0].length);
16883     
16884           item = {
16885             type: 'table',
16886             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16887             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16888             cells: cap[3].replace(/\n$/, '').split('\n')
16889           };
16890     
16891           for (i = 0; i < item.align.length; i++) {
16892             if (/^ *-+: *$/.test(item.align[i])) {
16893               item.align[i] = 'right';
16894             } else if (/^ *:-+: *$/.test(item.align[i])) {
16895               item.align[i] = 'center';
16896             } else if (/^ *:-+ *$/.test(item.align[i])) {
16897               item.align[i] = 'left';
16898             } else {
16899               item.align[i] = null;
16900             }
16901           }
16902     
16903           for (i = 0; i < item.cells.length; i++) {
16904             item.cells[i] = item.cells[i].split(/ *\| */);
16905           }
16906     
16907           this.tokens.push(item);
16908     
16909           continue;
16910         }
16911     
16912         // lheading
16913         if (cap = this.rules.lheading.exec(src)) {
16914           src = src.substring(cap[0].length);
16915           this.tokens.push({
16916             type: 'heading',
16917             depth: cap[2] === '=' ? 1 : 2,
16918             text: cap[1]
16919           });
16920           continue;
16921         }
16922     
16923         // hr
16924         if (cap = this.rules.hr.exec(src)) {
16925           src = src.substring(cap[0].length);
16926           this.tokens.push({
16927             type: 'hr'
16928           });
16929           continue;
16930         }
16931     
16932         // blockquote
16933         if (cap = this.rules.blockquote.exec(src)) {
16934           src = src.substring(cap[0].length);
16935     
16936           this.tokens.push({
16937             type: 'blockquote_start'
16938           });
16939     
16940           cap = cap[0].replace(/^ *> ?/gm, '');
16941     
16942           // Pass `top` to keep the current
16943           // "toplevel" state. This is exactly
16944           // how markdown.pl works.
16945           this.token(cap, top, true);
16946     
16947           this.tokens.push({
16948             type: 'blockquote_end'
16949           });
16950     
16951           continue;
16952         }
16953     
16954         // list
16955         if (cap = this.rules.list.exec(src)) {
16956           src = src.substring(cap[0].length);
16957           bull = cap[2];
16958     
16959           this.tokens.push({
16960             type: 'list_start',
16961             ordered: bull.length > 1
16962           });
16963     
16964           // Get each top-level item.
16965           cap = cap[0].match(this.rules.item);
16966     
16967           next = false;
16968           l = cap.length;
16969           i = 0;
16970     
16971           for (; i < l; i++) {
16972             item = cap[i];
16973     
16974             // Remove the list item's bullet
16975             // so it is seen as the next token.
16976             space = item.length;
16977             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16978     
16979             // Outdent whatever the
16980             // list item contains. Hacky.
16981             if (~item.indexOf('\n ')) {
16982               space -= item.length;
16983               item = !this.options.pedantic
16984                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16985                 : item.replace(/^ {1,4}/gm, '');
16986             }
16987     
16988             // Determine whether the next list item belongs here.
16989             // Backpedal if it does not belong in this list.
16990             if (this.options.smartLists && i !== l - 1) {
16991               b = block.bullet.exec(cap[i + 1])[0];
16992               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16993                 src = cap.slice(i + 1).join('\n') + src;
16994                 i = l - 1;
16995               }
16996             }
16997     
16998             // Determine whether item is loose or not.
16999             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17000             // for discount behavior.
17001             loose = next || /\n\n(?!\s*$)/.test(item);
17002             if (i !== l - 1) {
17003               next = item.charAt(item.length - 1) === '\n';
17004               if (!loose) { loose = next; }
17005             }
17006     
17007             this.tokens.push({
17008               type: loose
17009                 ? 'loose_item_start'
17010                 : 'list_item_start'
17011             });
17012     
17013             // Recurse.
17014             this.token(item, false, bq);
17015     
17016             this.tokens.push({
17017               type: 'list_item_end'
17018             });
17019           }
17020     
17021           this.tokens.push({
17022             type: 'list_end'
17023           });
17024     
17025           continue;
17026         }
17027     
17028         // html
17029         if (cap = this.rules.html.exec(src)) {
17030           src = src.substring(cap[0].length);
17031           this.tokens.push({
17032             type: this.options.sanitize
17033               ? 'paragraph'
17034               : 'html',
17035             pre: !this.options.sanitizer
17036               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17037             text: cap[0]
17038           });
17039           continue;
17040         }
17041     
17042         // def
17043         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17044           src = src.substring(cap[0].length);
17045           this.tokens.links[cap[1].toLowerCase()] = {
17046             href: cap[2],
17047             title: cap[3]
17048           };
17049           continue;
17050         }
17051     
17052         // table (gfm)
17053         if (top && (cap = this.rules.table.exec(src))) {
17054           src = src.substring(cap[0].length);
17055     
17056           item = {
17057             type: 'table',
17058             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17059             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17060             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17061           };
17062     
17063           for (i = 0; i < item.align.length; i++) {
17064             if (/^ *-+: *$/.test(item.align[i])) {
17065               item.align[i] = 'right';
17066             } else if (/^ *:-+: *$/.test(item.align[i])) {
17067               item.align[i] = 'center';
17068             } else if (/^ *:-+ *$/.test(item.align[i])) {
17069               item.align[i] = 'left';
17070             } else {
17071               item.align[i] = null;
17072             }
17073           }
17074     
17075           for (i = 0; i < item.cells.length; i++) {
17076             item.cells[i] = item.cells[i]
17077               .replace(/^ *\| *| *\| *$/g, '')
17078               .split(/ *\| */);
17079           }
17080     
17081           this.tokens.push(item);
17082     
17083           continue;
17084         }
17085     
17086         // top-level paragraph
17087         if (top && (cap = this.rules.paragraph.exec(src))) {
17088           src = src.substring(cap[0].length);
17089           this.tokens.push({
17090             type: 'paragraph',
17091             text: cap[1].charAt(cap[1].length - 1) === '\n'
17092               ? cap[1].slice(0, -1)
17093               : cap[1]
17094           });
17095           continue;
17096         }
17097     
17098         // text
17099         if (cap = this.rules.text.exec(src)) {
17100           // Top-level should never reach here.
17101           src = src.substring(cap[0].length);
17102           this.tokens.push({
17103             type: 'text',
17104             text: cap[0]
17105           });
17106           continue;
17107         }
17108     
17109         if (src) {
17110           throw new
17111             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17112         }
17113       }
17114     
17115       return this.tokens;
17116     };
17117     
17118     /**
17119      * Inline-Level Grammar
17120      */
17121     
17122     var inline = {
17123       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17124       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17125       url: noop,
17126       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17127       link: /^!?\[(inside)\]\(href\)/,
17128       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17129       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17130       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17131       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17132       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17133       br: /^ {2,}\n(?!\s*$)/,
17134       del: noop,
17135       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17136     };
17137     
17138     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17139     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17140     
17141     inline.link = replace(inline.link)
17142       ('inside', inline._inside)
17143       ('href', inline._href)
17144       ();
17145     
17146     inline.reflink = replace(inline.reflink)
17147       ('inside', inline._inside)
17148       ();
17149     
17150     /**
17151      * Normal Inline Grammar
17152      */
17153     
17154     inline.normal = merge({}, inline);
17155     
17156     /**
17157      * Pedantic Inline Grammar
17158      */
17159     
17160     inline.pedantic = merge({}, inline.normal, {
17161       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17162       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17163     });
17164     
17165     /**
17166      * GFM Inline Grammar
17167      */
17168     
17169     inline.gfm = merge({}, inline.normal, {
17170       escape: replace(inline.escape)('])', '~|])')(),
17171       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17172       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17173       text: replace(inline.text)
17174         (']|', '~]|')
17175         ('|', '|https?://|')
17176         ()
17177     });
17178     
17179     /**
17180      * GFM + Line Breaks Inline Grammar
17181      */
17182     
17183     inline.breaks = merge({}, inline.gfm, {
17184       br: replace(inline.br)('{2,}', '*')(),
17185       text: replace(inline.gfm.text)('{2,}', '*')()
17186     });
17187     
17188     /**
17189      * Inline Lexer & Compiler
17190      */
17191     
17192     function InlineLexer(links, options) {
17193       this.options = options || marked.defaults;
17194       this.links = links;
17195       this.rules = inline.normal;
17196       this.renderer = this.options.renderer || new Renderer;
17197       this.renderer.options = this.options;
17198     
17199       if (!this.links) {
17200         throw new
17201           Error('Tokens array requires a `links` property.');
17202       }
17203     
17204       if (this.options.gfm) {
17205         if (this.options.breaks) {
17206           this.rules = inline.breaks;
17207         } else {
17208           this.rules = inline.gfm;
17209         }
17210       } else if (this.options.pedantic) {
17211         this.rules = inline.pedantic;
17212       }
17213     }
17214     
17215     /**
17216      * Expose Inline Rules
17217      */
17218     
17219     InlineLexer.rules = inline;
17220     
17221     /**
17222      * Static Lexing/Compiling Method
17223      */
17224     
17225     InlineLexer.output = function(src, links, options) {
17226       var inline = new InlineLexer(links, options);
17227       return inline.output(src);
17228     };
17229     
17230     /**
17231      * Lexing/Compiling
17232      */
17233     
17234     InlineLexer.prototype.output = function(src) {
17235       var out = ''
17236         , link
17237         , text
17238         , href
17239         , cap;
17240     
17241       while (src) {
17242         // escape
17243         if (cap = this.rules.escape.exec(src)) {
17244           src = src.substring(cap[0].length);
17245           out += cap[1];
17246           continue;
17247         }
17248     
17249         // autolink
17250         if (cap = this.rules.autolink.exec(src)) {
17251           src = src.substring(cap[0].length);
17252           if (cap[2] === '@') {
17253             text = cap[1].charAt(6) === ':'
17254               ? this.mangle(cap[1].substring(7))
17255               : this.mangle(cap[1]);
17256             href = this.mangle('mailto:') + text;
17257           } else {
17258             text = escape(cap[1]);
17259             href = text;
17260           }
17261           out += this.renderer.link(href, null, text);
17262           continue;
17263         }
17264     
17265         // url (gfm)
17266         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17267           src = src.substring(cap[0].length);
17268           text = escape(cap[1]);
17269           href = text;
17270           out += this.renderer.link(href, null, text);
17271           continue;
17272         }
17273     
17274         // tag
17275         if (cap = this.rules.tag.exec(src)) {
17276           if (!this.inLink && /^<a /i.test(cap[0])) {
17277             this.inLink = true;
17278           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17279             this.inLink = false;
17280           }
17281           src = src.substring(cap[0].length);
17282           out += this.options.sanitize
17283             ? this.options.sanitizer
17284               ? this.options.sanitizer(cap[0])
17285               : escape(cap[0])
17286             : cap[0];
17287           continue;
17288         }
17289     
17290         // link
17291         if (cap = this.rules.link.exec(src)) {
17292           src = src.substring(cap[0].length);
17293           this.inLink = true;
17294           out += this.outputLink(cap, {
17295             href: cap[2],
17296             title: cap[3]
17297           });
17298           this.inLink = false;
17299           continue;
17300         }
17301     
17302         // reflink, nolink
17303         if ((cap = this.rules.reflink.exec(src))
17304             || (cap = this.rules.nolink.exec(src))) {
17305           src = src.substring(cap[0].length);
17306           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17307           link = this.links[link.toLowerCase()];
17308           if (!link || !link.href) {
17309             out += cap[0].charAt(0);
17310             src = cap[0].substring(1) + src;
17311             continue;
17312           }
17313           this.inLink = true;
17314           out += this.outputLink(cap, link);
17315           this.inLink = false;
17316           continue;
17317         }
17318     
17319         // strong
17320         if (cap = this.rules.strong.exec(src)) {
17321           src = src.substring(cap[0].length);
17322           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17323           continue;
17324         }
17325     
17326         // em
17327         if (cap = this.rules.em.exec(src)) {
17328           src = src.substring(cap[0].length);
17329           out += this.renderer.em(this.output(cap[2] || cap[1]));
17330           continue;
17331         }
17332     
17333         // code
17334         if (cap = this.rules.code.exec(src)) {
17335           src = src.substring(cap[0].length);
17336           out += this.renderer.codespan(escape(cap[2], true));
17337           continue;
17338         }
17339     
17340         // br
17341         if (cap = this.rules.br.exec(src)) {
17342           src = src.substring(cap[0].length);
17343           out += this.renderer.br();
17344           continue;
17345         }
17346     
17347         // del (gfm)
17348         if (cap = this.rules.del.exec(src)) {
17349           src = src.substring(cap[0].length);
17350           out += this.renderer.del(this.output(cap[1]));
17351           continue;
17352         }
17353     
17354         // text
17355         if (cap = this.rules.text.exec(src)) {
17356           src = src.substring(cap[0].length);
17357           out += this.renderer.text(escape(this.smartypants(cap[0])));
17358           continue;
17359         }
17360     
17361         if (src) {
17362           throw new
17363             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17364         }
17365       }
17366     
17367       return out;
17368     };
17369     
17370     /**
17371      * Compile Link
17372      */
17373     
17374     InlineLexer.prototype.outputLink = function(cap, link) {
17375       var href = escape(link.href)
17376         , title = link.title ? escape(link.title) : null;
17377     
17378       return cap[0].charAt(0) !== '!'
17379         ? this.renderer.link(href, title, this.output(cap[1]))
17380         : this.renderer.image(href, title, escape(cap[1]));
17381     };
17382     
17383     /**
17384      * Smartypants Transformations
17385      */
17386     
17387     InlineLexer.prototype.smartypants = function(text) {
17388       if (!this.options.smartypants)  { return text; }
17389       return text
17390         // em-dashes
17391         .replace(/---/g, '\u2014')
17392         // en-dashes
17393         .replace(/--/g, '\u2013')
17394         // opening singles
17395         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17396         // closing singles & apostrophes
17397         .replace(/'/g, '\u2019')
17398         // opening doubles
17399         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17400         // closing doubles
17401         .replace(/"/g, '\u201d')
17402         // ellipses
17403         .replace(/\.{3}/g, '\u2026');
17404     };
17405     
17406     /**
17407      * Mangle Links
17408      */
17409     
17410     InlineLexer.prototype.mangle = function(text) {
17411       if (!this.options.mangle) { return text; }
17412       var out = ''
17413         , l = text.length
17414         , i = 0
17415         , ch;
17416     
17417       for (; i < l; i++) {
17418         ch = text.charCodeAt(i);
17419         if (Math.random() > 0.5) {
17420           ch = 'x' + ch.toString(16);
17421         }
17422         out += '&#' + ch + ';';
17423       }
17424     
17425       return out;
17426     };
17427     
17428     /**
17429      * Renderer
17430      */
17431     
17432     function Renderer(options) {
17433       this.options = options || {};
17434     }
17435     
17436     Renderer.prototype.code = function(code, lang, escaped) {
17437       if (this.options.highlight) {
17438         var out = this.options.highlight(code, lang);
17439         if (out != null && out !== code) {
17440           escaped = true;
17441           code = out;
17442         }
17443       } else {
17444             // hack!!! - it's already escapeD?
17445             escaped = true;
17446       }
17447     
17448       if (!lang) {
17449         return '<pre><code>'
17450           + (escaped ? code : escape(code, true))
17451           + '\n</code></pre>';
17452       }
17453     
17454       return '<pre><code class="'
17455         + this.options.langPrefix
17456         + escape(lang, true)
17457         + '">'
17458         + (escaped ? code : escape(code, true))
17459         + '\n</code></pre>\n';
17460     };
17461     
17462     Renderer.prototype.blockquote = function(quote) {
17463       return '<blockquote>\n' + quote + '</blockquote>\n';
17464     };
17465     
17466     Renderer.prototype.html = function(html) {
17467       return html;
17468     };
17469     
17470     Renderer.prototype.heading = function(text, level, raw) {
17471       return '<h'
17472         + level
17473         + ' id="'
17474         + this.options.headerPrefix
17475         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17476         + '">'
17477         + text
17478         + '</h'
17479         + level
17480         + '>\n';
17481     };
17482     
17483     Renderer.prototype.hr = function() {
17484       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17485     };
17486     
17487     Renderer.prototype.list = function(body, ordered) {
17488       var type = ordered ? 'ol' : 'ul';
17489       return '<' + type + '>\n' + body + '</' + type + '>\n';
17490     };
17491     
17492     Renderer.prototype.listitem = function(text) {
17493       return '<li>' + text + '</li>\n';
17494     };
17495     
17496     Renderer.prototype.paragraph = function(text) {
17497       return '<p>' + text + '</p>\n';
17498     };
17499     
17500     Renderer.prototype.table = function(header, body) {
17501       return '<table class="table table-striped">\n'
17502         + '<thead>\n'
17503         + header
17504         + '</thead>\n'
17505         + '<tbody>\n'
17506         + body
17507         + '</tbody>\n'
17508         + '</table>\n';
17509     };
17510     
17511     Renderer.prototype.tablerow = function(content) {
17512       return '<tr>\n' + content + '</tr>\n';
17513     };
17514     
17515     Renderer.prototype.tablecell = function(content, flags) {
17516       var type = flags.header ? 'th' : 'td';
17517       var tag = flags.align
17518         ? '<' + type + ' style="text-align:' + flags.align + '">'
17519         : '<' + type + '>';
17520       return tag + content + '</' + type + '>\n';
17521     };
17522     
17523     // span level renderer
17524     Renderer.prototype.strong = function(text) {
17525       return '<strong>' + text + '</strong>';
17526     };
17527     
17528     Renderer.prototype.em = function(text) {
17529       return '<em>' + text + '</em>';
17530     };
17531     
17532     Renderer.prototype.codespan = function(text) {
17533       return '<code>' + text + '</code>';
17534     };
17535     
17536     Renderer.prototype.br = function() {
17537       return this.options.xhtml ? '<br/>' : '<br>';
17538     };
17539     
17540     Renderer.prototype.del = function(text) {
17541       return '<del>' + text + '</del>';
17542     };
17543     
17544     Renderer.prototype.link = function(href, title, text) {
17545       if (this.options.sanitize) {
17546         try {
17547           var prot = decodeURIComponent(unescape(href))
17548             .replace(/[^\w:]/g, '')
17549             .toLowerCase();
17550         } catch (e) {
17551           return '';
17552         }
17553         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17554           return '';
17555         }
17556       }
17557       var out = '<a href="' + href + '"';
17558       if (title) {
17559         out += ' title="' + title + '"';
17560       }
17561       out += '>' + text + '</a>';
17562       return out;
17563     };
17564     
17565     Renderer.prototype.image = function(href, title, text) {
17566       var out = '<img src="' + href + '" alt="' + text + '"';
17567       if (title) {
17568         out += ' title="' + title + '"';
17569       }
17570       out += this.options.xhtml ? '/>' : '>';
17571       return out;
17572     };
17573     
17574     Renderer.prototype.text = function(text) {
17575       return text;
17576     };
17577     
17578     /**
17579      * Parsing & Compiling
17580      */
17581     
17582     function Parser(options) {
17583       this.tokens = [];
17584       this.token = null;
17585       this.options = options || marked.defaults;
17586       this.options.renderer = this.options.renderer || new Renderer;
17587       this.renderer = this.options.renderer;
17588       this.renderer.options = this.options;
17589     }
17590     
17591     /**
17592      * Static Parse Method
17593      */
17594     
17595     Parser.parse = function(src, options, renderer) {
17596       var parser = new Parser(options, renderer);
17597       return parser.parse(src);
17598     };
17599     
17600     /**
17601      * Parse Loop
17602      */
17603     
17604     Parser.prototype.parse = function(src) {
17605       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17606       this.tokens = src.reverse();
17607     
17608       var out = '';
17609       while (this.next()) {
17610         out += this.tok();
17611       }
17612     
17613       return out;
17614     };
17615     
17616     /**
17617      * Next Token
17618      */
17619     
17620     Parser.prototype.next = function() {
17621       return this.token = this.tokens.pop();
17622     };
17623     
17624     /**
17625      * Preview Next Token
17626      */
17627     
17628     Parser.prototype.peek = function() {
17629       return this.tokens[this.tokens.length - 1] || 0;
17630     };
17631     
17632     /**
17633      * Parse Text Tokens
17634      */
17635     
17636     Parser.prototype.parseText = function() {
17637       var body = this.token.text;
17638     
17639       while (this.peek().type === 'text') {
17640         body += '\n' + this.next().text;
17641       }
17642     
17643       return this.inline.output(body);
17644     };
17645     
17646     /**
17647      * Parse Current Token
17648      */
17649     
17650     Parser.prototype.tok = function() {
17651       switch (this.token.type) {
17652         case 'space': {
17653           return '';
17654         }
17655         case 'hr': {
17656           return this.renderer.hr();
17657         }
17658         case 'heading': {
17659           return this.renderer.heading(
17660             this.inline.output(this.token.text),
17661             this.token.depth,
17662             this.token.text);
17663         }
17664         case 'code': {
17665           return this.renderer.code(this.token.text,
17666             this.token.lang,
17667             this.token.escaped);
17668         }
17669         case 'table': {
17670           var header = ''
17671             , body = ''
17672             , i
17673             , row
17674             , cell
17675             , flags
17676             , j;
17677     
17678           // header
17679           cell = '';
17680           for (i = 0; i < this.token.header.length; i++) {
17681             flags = { header: true, align: this.token.align[i] };
17682             cell += this.renderer.tablecell(
17683               this.inline.output(this.token.header[i]),
17684               { header: true, align: this.token.align[i] }
17685             );
17686           }
17687           header += this.renderer.tablerow(cell);
17688     
17689           for (i = 0; i < this.token.cells.length; i++) {
17690             row = this.token.cells[i];
17691     
17692             cell = '';
17693             for (j = 0; j < row.length; j++) {
17694               cell += this.renderer.tablecell(
17695                 this.inline.output(row[j]),
17696                 { header: false, align: this.token.align[j] }
17697               );
17698             }
17699     
17700             body += this.renderer.tablerow(cell);
17701           }
17702           return this.renderer.table(header, body);
17703         }
17704         case 'blockquote_start': {
17705           var body = '';
17706     
17707           while (this.next().type !== 'blockquote_end') {
17708             body += this.tok();
17709           }
17710     
17711           return this.renderer.blockquote(body);
17712         }
17713         case 'list_start': {
17714           var body = ''
17715             , ordered = this.token.ordered;
17716     
17717           while (this.next().type !== 'list_end') {
17718             body += this.tok();
17719           }
17720     
17721           return this.renderer.list(body, ordered);
17722         }
17723         case 'list_item_start': {
17724           var body = '';
17725     
17726           while (this.next().type !== 'list_item_end') {
17727             body += this.token.type === 'text'
17728               ? this.parseText()
17729               : this.tok();
17730           }
17731     
17732           return this.renderer.listitem(body);
17733         }
17734         case 'loose_item_start': {
17735           var body = '';
17736     
17737           while (this.next().type !== 'list_item_end') {
17738             body += this.tok();
17739           }
17740     
17741           return this.renderer.listitem(body);
17742         }
17743         case 'html': {
17744           var html = !this.token.pre && !this.options.pedantic
17745             ? this.inline.output(this.token.text)
17746             : this.token.text;
17747           return this.renderer.html(html);
17748         }
17749         case 'paragraph': {
17750           return this.renderer.paragraph(this.inline.output(this.token.text));
17751         }
17752         case 'text': {
17753           return this.renderer.paragraph(this.parseText());
17754         }
17755       }
17756     };
17757     
17758     /**
17759      * Helpers
17760      */
17761     
17762     function escape(html, encode) {
17763       return html
17764         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17765         .replace(/</g, '&lt;')
17766         .replace(/>/g, '&gt;')
17767         .replace(/"/g, '&quot;')
17768         .replace(/'/g, '&#39;');
17769     }
17770     
17771     function unescape(html) {
17772         // explicitly match decimal, hex, and named HTML entities 
17773       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17774         n = n.toLowerCase();
17775         if (n === 'colon') { return ':'; }
17776         if (n.charAt(0) === '#') {
17777           return n.charAt(1) === 'x'
17778             ? String.fromCharCode(parseInt(n.substring(2), 16))
17779             : String.fromCharCode(+n.substring(1));
17780         }
17781         return '';
17782       });
17783     }
17784     
17785     function replace(regex, opt) {
17786       regex = regex.source;
17787       opt = opt || '';
17788       return function self(name, val) {
17789         if (!name) { return new RegExp(regex, opt); }
17790         val = val.source || val;
17791         val = val.replace(/(^|[^\[])\^/g, '$1');
17792         regex = regex.replace(name, val);
17793         return self;
17794       };
17795     }
17796     
17797     function noop() {}
17798     noop.exec = noop;
17799     
17800     function merge(obj) {
17801       var i = 1
17802         , target
17803         , key;
17804     
17805       for (; i < arguments.length; i++) {
17806         target = arguments[i];
17807         for (key in target) {
17808           if (Object.prototype.hasOwnProperty.call(target, key)) {
17809             obj[key] = target[key];
17810           }
17811         }
17812       }
17813     
17814       return obj;
17815     }
17816     
17817     
17818     /**
17819      * Marked
17820      */
17821     
17822     function marked(src, opt, callback) {
17823       if (callback || typeof opt === 'function') {
17824         if (!callback) {
17825           callback = opt;
17826           opt = null;
17827         }
17828     
17829         opt = merge({}, marked.defaults, opt || {});
17830     
17831         var highlight = opt.highlight
17832           , tokens
17833           , pending
17834           , i = 0;
17835     
17836         try {
17837           tokens = Lexer.lex(src, opt)
17838         } catch (e) {
17839           return callback(e);
17840         }
17841     
17842         pending = tokens.length;
17843     
17844         var done = function(err) {
17845           if (err) {
17846             opt.highlight = highlight;
17847             return callback(err);
17848           }
17849     
17850           var out;
17851     
17852           try {
17853             out = Parser.parse(tokens, opt);
17854           } catch (e) {
17855             err = e;
17856           }
17857     
17858           opt.highlight = highlight;
17859     
17860           return err
17861             ? callback(err)
17862             : callback(null, out);
17863         };
17864     
17865         if (!highlight || highlight.length < 3) {
17866           return done();
17867         }
17868     
17869         delete opt.highlight;
17870     
17871         if (!pending) { return done(); }
17872     
17873         for (; i < tokens.length; i++) {
17874           (function(token) {
17875             if (token.type !== 'code') {
17876               return --pending || done();
17877             }
17878             return highlight(token.text, token.lang, function(err, code) {
17879               if (err) { return done(err); }
17880               if (code == null || code === token.text) {
17881                 return --pending || done();
17882               }
17883               token.text = code;
17884               token.escaped = true;
17885               --pending || done();
17886             });
17887           })(tokens[i]);
17888         }
17889     
17890         return;
17891       }
17892       try {
17893         if (opt) { opt = merge({}, marked.defaults, opt); }
17894         return Parser.parse(Lexer.lex(src, opt), opt);
17895       } catch (e) {
17896         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17897         if ((opt || marked.defaults).silent) {
17898           return '<p>An error occured:</p><pre>'
17899             + escape(e.message + '', true)
17900             + '</pre>';
17901         }
17902         throw e;
17903       }
17904     }
17905     
17906     /**
17907      * Options
17908      */
17909     
17910     marked.options =
17911     marked.setOptions = function(opt) {
17912       merge(marked.defaults, opt);
17913       return marked;
17914     };
17915     
17916     marked.defaults = {
17917       gfm: true,
17918       tables: true,
17919       breaks: false,
17920       pedantic: false,
17921       sanitize: false,
17922       sanitizer: null,
17923       mangle: true,
17924       smartLists: false,
17925       silent: false,
17926       highlight: null,
17927       langPrefix: 'lang-',
17928       smartypants: false,
17929       headerPrefix: '',
17930       renderer: new Renderer,
17931       xhtml: false
17932     };
17933     
17934     /**
17935      * Expose
17936      */
17937     
17938     marked.Parser = Parser;
17939     marked.parser = Parser.parse;
17940     
17941     marked.Renderer = Renderer;
17942     
17943     marked.Lexer = Lexer;
17944     marked.lexer = Lexer.lex;
17945     
17946     marked.InlineLexer = InlineLexer;
17947     marked.inlineLexer = InlineLexer.output;
17948     
17949     marked.parse = marked;
17950     
17951     Roo.Markdown.marked = marked;
17952
17953 })();/*
17954  * Based on:
17955  * Ext JS Library 1.1.1
17956  * Copyright(c) 2006-2007, Ext JS, LLC.
17957  *
17958  * Originally Released Under LGPL - original licence link has changed is not relivant.
17959  *
17960  * Fork - LGPL
17961  * <script type="text/javascript">
17962  */
17963
17964
17965
17966 /*
17967  * These classes are derivatives of the similarly named classes in the YUI Library.
17968  * The original license:
17969  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17970  * Code licensed under the BSD License:
17971  * http://developer.yahoo.net/yui/license.txt
17972  */
17973
17974 (function() {
17975
17976 var Event=Roo.EventManager;
17977 var Dom=Roo.lib.Dom;
17978
17979 /**
17980  * @class Roo.dd.DragDrop
17981  * @extends Roo.util.Observable
17982  * Defines the interface and base operation of items that that can be
17983  * dragged or can be drop targets.  It was designed to be extended, overriding
17984  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17985  * Up to three html elements can be associated with a DragDrop instance:
17986  * <ul>
17987  * <li>linked element: the element that is passed into the constructor.
17988  * This is the element which defines the boundaries for interaction with
17989  * other DragDrop objects.</li>
17990  * <li>handle element(s): The drag operation only occurs if the element that
17991  * was clicked matches a handle element.  By default this is the linked
17992  * element, but there are times that you will want only a portion of the
17993  * linked element to initiate the drag operation, and the setHandleElId()
17994  * method provides a way to define this.</li>
17995  * <li>drag element: this represents the element that would be moved along
17996  * with the cursor during a drag operation.  By default, this is the linked
17997  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17998  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17999  * </li>
18000  * </ul>
18001  * This class should not be instantiated until the onload event to ensure that
18002  * the associated elements are available.
18003  * The following would define a DragDrop obj that would interact with any
18004  * other DragDrop obj in the "group1" group:
18005  * <pre>
18006  *  dd = new Roo.dd.DragDrop("div1", "group1");
18007  * </pre>
18008  * Since none of the event handlers have been implemented, nothing would
18009  * actually happen if you were to run the code above.  Normally you would
18010  * override this class or one of the default implementations, but you can
18011  * also override the methods you want on an instance of the class...
18012  * <pre>
18013  *  dd.onDragDrop = function(e, id) {
18014  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18015  *  }
18016  * </pre>
18017  * @constructor
18018  * @param {String} id of the element that is linked to this instance
18019  * @param {String} sGroup the group of related DragDrop objects
18020  * @param {object} config an object containing configurable attributes
18021  *                Valid properties for DragDrop:
18022  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18023  */
18024 Roo.dd.DragDrop = function(id, sGroup, config) {
18025     if (id) {
18026         this.init(id, sGroup, config);
18027     }
18028     
18029 };
18030
18031 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18032
18033     /**
18034      * The id of the element associated with this object.  This is what we
18035      * refer to as the "linked element" because the size and position of
18036      * this element is used to determine when the drag and drop objects have
18037      * interacted.
18038      * @property id
18039      * @type String
18040      */
18041     id: null,
18042
18043     /**
18044      * Configuration attributes passed into the constructor
18045      * @property config
18046      * @type object
18047      */
18048     config: null,
18049
18050     /**
18051      * The id of the element that will be dragged.  By default this is same
18052      * as the linked element , but could be changed to another element. Ex:
18053      * Roo.dd.DDProxy
18054      * @property dragElId
18055      * @type String
18056      * @private
18057      */
18058     dragElId: null,
18059
18060     /**
18061      * the id of the element that initiates the drag operation.  By default
18062      * this is the linked element, but could be changed to be a child of this
18063      * element.  This lets us do things like only starting the drag when the
18064      * header element within the linked html element is clicked.
18065      * @property handleElId
18066      * @type String
18067      * @private
18068      */
18069     handleElId: null,
18070
18071     /**
18072      * An associative array of HTML tags that will be ignored if clicked.
18073      * @property invalidHandleTypes
18074      * @type {string: string}
18075      */
18076     invalidHandleTypes: null,
18077
18078     /**
18079      * An associative array of ids for elements that will be ignored if clicked
18080      * @property invalidHandleIds
18081      * @type {string: string}
18082      */
18083     invalidHandleIds: null,
18084
18085     /**
18086      * An indexted array of css class names for elements that will be ignored
18087      * if clicked.
18088      * @property invalidHandleClasses
18089      * @type string[]
18090      */
18091     invalidHandleClasses: null,
18092
18093     /**
18094      * The linked element's absolute X position at the time the drag was
18095      * started
18096      * @property startPageX
18097      * @type int
18098      * @private
18099      */
18100     startPageX: 0,
18101
18102     /**
18103      * The linked element's absolute X position at the time the drag was
18104      * started
18105      * @property startPageY
18106      * @type int
18107      * @private
18108      */
18109     startPageY: 0,
18110
18111     /**
18112      * The group defines a logical collection of DragDrop objects that are
18113      * related.  Instances only get events when interacting with other
18114      * DragDrop object in the same group.  This lets us define multiple
18115      * groups using a single DragDrop subclass if we want.
18116      * @property groups
18117      * @type {string: string}
18118      */
18119     groups: null,
18120
18121     /**
18122      * Individual drag/drop instances can be locked.  This will prevent
18123      * onmousedown start drag.
18124      * @property locked
18125      * @type boolean
18126      * @private
18127      */
18128     locked: false,
18129
18130     /**
18131      * Lock this instance
18132      * @method lock
18133      */
18134     lock: function() { this.locked = true; },
18135
18136     /**
18137      * Unlock this instace
18138      * @method unlock
18139      */
18140     unlock: function() { this.locked = false; },
18141
18142     /**
18143      * By default, all insances can be a drop target.  This can be disabled by
18144      * setting isTarget to false.
18145      * @method isTarget
18146      * @type boolean
18147      */
18148     isTarget: true,
18149
18150     /**
18151      * The padding configured for this drag and drop object for calculating
18152      * the drop zone intersection with this object.
18153      * @method padding
18154      * @type int[]
18155      */
18156     padding: null,
18157
18158     /**
18159      * Cached reference to the linked element
18160      * @property _domRef
18161      * @private
18162      */
18163     _domRef: null,
18164
18165     /**
18166      * Internal typeof flag
18167      * @property __ygDragDrop
18168      * @private
18169      */
18170     __ygDragDrop: true,
18171
18172     /**
18173      * Set to true when horizontal contraints are applied
18174      * @property constrainX
18175      * @type boolean
18176      * @private
18177      */
18178     constrainX: false,
18179
18180     /**
18181      * Set to true when vertical contraints are applied
18182      * @property constrainY
18183      * @type boolean
18184      * @private
18185      */
18186     constrainY: false,
18187
18188     /**
18189      * The left constraint
18190      * @property minX
18191      * @type int
18192      * @private
18193      */
18194     minX: 0,
18195
18196     /**
18197      * The right constraint
18198      * @property maxX
18199      * @type int
18200      * @private
18201      */
18202     maxX: 0,
18203
18204     /**
18205      * The up constraint
18206      * @property minY
18207      * @type int
18208      * @type int
18209      * @private
18210      */
18211     minY: 0,
18212
18213     /**
18214      * The down constraint
18215      * @property maxY
18216      * @type int
18217      * @private
18218      */
18219     maxY: 0,
18220
18221     /**
18222      * Maintain offsets when we resetconstraints.  Set to true when you want
18223      * the position of the element relative to its parent to stay the same
18224      * when the page changes
18225      *
18226      * @property maintainOffset
18227      * @type boolean
18228      */
18229     maintainOffset: false,
18230
18231     /**
18232      * Array of pixel locations the element will snap to if we specified a
18233      * horizontal graduation/interval.  This array is generated automatically
18234      * when you define a tick interval.
18235      * @property xTicks
18236      * @type int[]
18237      */
18238     xTicks: null,
18239
18240     /**
18241      * Array of pixel locations the element will snap to if we specified a
18242      * vertical graduation/interval.  This array is generated automatically
18243      * when you define a tick interval.
18244      * @property yTicks
18245      * @type int[]
18246      */
18247     yTicks: null,
18248
18249     /**
18250      * By default the drag and drop instance will only respond to the primary
18251      * button click (left button for a right-handed mouse).  Set to true to
18252      * allow drag and drop to start with any mouse click that is propogated
18253      * by the browser
18254      * @property primaryButtonOnly
18255      * @type boolean
18256      */
18257     primaryButtonOnly: true,
18258
18259     /**
18260      * The availabe property is false until the linked dom element is accessible.
18261      * @property available
18262      * @type boolean
18263      */
18264     available: false,
18265
18266     /**
18267      * By default, drags can only be initiated if the mousedown occurs in the
18268      * region the linked element is.  This is done in part to work around a
18269      * bug in some browsers that mis-report the mousedown if the previous
18270      * mouseup happened outside of the window.  This property is set to true
18271      * if outer handles are defined.
18272      *
18273      * @property hasOuterHandles
18274      * @type boolean
18275      * @default false
18276      */
18277     hasOuterHandles: false,
18278
18279     /**
18280      * Code that executes immediately before the startDrag event
18281      * @method b4StartDrag
18282      * @private
18283      */
18284     b4StartDrag: function(x, y) { },
18285
18286     /**
18287      * Abstract method called after a drag/drop object is clicked
18288      * and the drag or mousedown time thresholds have beeen met.
18289      * @method startDrag
18290      * @param {int} X click location
18291      * @param {int} Y click location
18292      */
18293     startDrag: function(x, y) { /* override this */ },
18294
18295     /**
18296      * Code that executes immediately before the onDrag event
18297      * @method b4Drag
18298      * @private
18299      */
18300     b4Drag: function(e) { },
18301
18302     /**
18303      * Abstract method called during the onMouseMove event while dragging an
18304      * object.
18305      * @method onDrag
18306      * @param {Event} e the mousemove event
18307      */
18308     onDrag: function(e) { /* override this */ },
18309
18310     /**
18311      * Abstract method called when this element fist begins hovering over
18312      * another DragDrop obj
18313      * @method onDragEnter
18314      * @param {Event} e the mousemove event
18315      * @param {String|DragDrop[]} id In POINT mode, the element
18316      * id this is hovering over.  In INTERSECT mode, an array of one or more
18317      * dragdrop items being hovered over.
18318      */
18319     onDragEnter: function(e, id) { /* override this */ },
18320
18321     /**
18322      * Code that executes immediately before the onDragOver event
18323      * @method b4DragOver
18324      * @private
18325      */
18326     b4DragOver: function(e) { },
18327
18328     /**
18329      * Abstract method called when this element is hovering over another
18330      * DragDrop obj
18331      * @method onDragOver
18332      * @param {Event} e the mousemove event
18333      * @param {String|DragDrop[]} id In POINT mode, the element
18334      * id this is hovering over.  In INTERSECT mode, an array of dd items
18335      * being hovered over.
18336      */
18337     onDragOver: function(e, id) { /* override this */ },
18338
18339     /**
18340      * Code that executes immediately before the onDragOut event
18341      * @method b4DragOut
18342      * @private
18343      */
18344     b4DragOut: function(e) { },
18345
18346     /**
18347      * Abstract method called when we are no longer hovering over an element
18348      * @method onDragOut
18349      * @param {Event} e the mousemove event
18350      * @param {String|DragDrop[]} id In POINT mode, the element
18351      * id this was hovering over.  In INTERSECT mode, an array of dd items
18352      * that the mouse is no longer over.
18353      */
18354     onDragOut: function(e, id) { /* override this */ },
18355
18356     /**
18357      * Code that executes immediately before the onDragDrop event
18358      * @method b4DragDrop
18359      * @private
18360      */
18361     b4DragDrop: function(e) { },
18362
18363     /**
18364      * Abstract method called when this item is dropped on another DragDrop
18365      * obj
18366      * @method onDragDrop
18367      * @param {Event} e the mouseup event
18368      * @param {String|DragDrop[]} id In POINT mode, the element
18369      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18370      * was dropped on.
18371      */
18372     onDragDrop: function(e, id) { /* override this */ },
18373
18374     /**
18375      * Abstract method called when this item is dropped on an area with no
18376      * drop target
18377      * @method onInvalidDrop
18378      * @param {Event} e the mouseup event
18379      */
18380     onInvalidDrop: function(e) { /* override this */ },
18381
18382     /**
18383      * Code that executes immediately before the endDrag event
18384      * @method b4EndDrag
18385      * @private
18386      */
18387     b4EndDrag: function(e) { },
18388
18389     /**
18390      * Fired when we are done dragging the object
18391      * @method endDrag
18392      * @param {Event} e the mouseup event
18393      */
18394     endDrag: function(e) { /* override this */ },
18395
18396     /**
18397      * Code executed immediately before the onMouseDown event
18398      * @method b4MouseDown
18399      * @param {Event} e the mousedown event
18400      * @private
18401      */
18402     b4MouseDown: function(e) {  },
18403
18404     /**
18405      * Event handler that fires when a drag/drop obj gets a mousedown
18406      * @method onMouseDown
18407      * @param {Event} e the mousedown event
18408      */
18409     onMouseDown: function(e) { /* override this */ },
18410
18411     /**
18412      * Event handler that fires when a drag/drop obj gets a mouseup
18413      * @method onMouseUp
18414      * @param {Event} e the mouseup event
18415      */
18416     onMouseUp: function(e) { /* override this */ },
18417
18418     /**
18419      * Override the onAvailable method to do what is needed after the initial
18420      * position was determined.
18421      * @method onAvailable
18422      */
18423     onAvailable: function () {
18424     },
18425
18426     /*
18427      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18428      * @type Object
18429      */
18430     defaultPadding : {left:0, right:0, top:0, bottom:0},
18431
18432     /*
18433      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18434  *
18435  * Usage:
18436  <pre><code>
18437  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18438                 { dragElId: "existingProxyDiv" });
18439  dd.startDrag = function(){
18440      this.constrainTo("parent-id");
18441  };
18442  </code></pre>
18443  * Or you can initalize it using the {@link Roo.Element} object:
18444  <pre><code>
18445  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18446      startDrag : function(){
18447          this.constrainTo("parent-id");
18448      }
18449  });
18450  </code></pre>
18451      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18452      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18453      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18454      * an object containing the sides to pad. For example: {right:10, bottom:10}
18455      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18456      */
18457     constrainTo : function(constrainTo, pad, inContent){
18458         if(typeof pad == "number"){
18459             pad = {left: pad, right:pad, top:pad, bottom:pad};
18460         }
18461         pad = pad || this.defaultPadding;
18462         var b = Roo.get(this.getEl()).getBox();
18463         var ce = Roo.get(constrainTo);
18464         var s = ce.getScroll();
18465         var c, cd = ce.dom;
18466         if(cd == document.body){
18467             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18468         }else{
18469             xy = ce.getXY();
18470             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18471         }
18472
18473
18474         var topSpace = b.y - c.y;
18475         var leftSpace = b.x - c.x;
18476
18477         this.resetConstraints();
18478         this.setXConstraint(leftSpace - (pad.left||0), // left
18479                 c.width - leftSpace - b.width - (pad.right||0) //right
18480         );
18481         this.setYConstraint(topSpace - (pad.top||0), //top
18482                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18483         );
18484     },
18485
18486     /**
18487      * Returns a reference to the linked element
18488      * @method getEl
18489      * @return {HTMLElement} the html element
18490      */
18491     getEl: function() {
18492         if (!this._domRef) {
18493             this._domRef = Roo.getDom(this.id);
18494         }
18495
18496         return this._domRef;
18497     },
18498
18499     /**
18500      * Returns a reference to the actual element to drag.  By default this is
18501      * the same as the html element, but it can be assigned to another
18502      * element. An example of this can be found in Roo.dd.DDProxy
18503      * @method getDragEl
18504      * @return {HTMLElement} the html element
18505      */
18506     getDragEl: function() {
18507         return Roo.getDom(this.dragElId);
18508     },
18509
18510     /**
18511      * Sets up the DragDrop object.  Must be called in the constructor of any
18512      * Roo.dd.DragDrop subclass
18513      * @method init
18514      * @param id the id of the linked element
18515      * @param {String} sGroup the group of related items
18516      * @param {object} config configuration attributes
18517      */
18518     init: function(id, sGroup, config) {
18519         this.initTarget(id, sGroup, config);
18520         if (!Roo.isTouch) {
18521             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18522         }
18523         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18524         // Event.on(this.id, "selectstart", Event.preventDefault);
18525     },
18526
18527     /**
18528      * Initializes Targeting functionality only... the object does not
18529      * get a mousedown handler.
18530      * @method initTarget
18531      * @param id the id of the linked element
18532      * @param {String} sGroup the group of related items
18533      * @param {object} config configuration attributes
18534      */
18535     initTarget: function(id, sGroup, config) {
18536
18537         // configuration attributes
18538         this.config = config || {};
18539
18540         // create a local reference to the drag and drop manager
18541         this.DDM = Roo.dd.DDM;
18542         // initialize the groups array
18543         this.groups = {};
18544
18545         // assume that we have an element reference instead of an id if the
18546         // parameter is not a string
18547         if (typeof id !== "string") {
18548             id = Roo.id(id);
18549         }
18550
18551         // set the id
18552         this.id = id;
18553
18554         // add to an interaction group
18555         this.addToGroup((sGroup) ? sGroup : "default");
18556
18557         // We don't want to register this as the handle with the manager
18558         // so we just set the id rather than calling the setter.
18559         this.handleElId = id;
18560
18561         // the linked element is the element that gets dragged by default
18562         this.setDragElId(id);
18563
18564         // by default, clicked anchors will not start drag operations.
18565         this.invalidHandleTypes = { A: "A" };
18566         this.invalidHandleIds = {};
18567         this.invalidHandleClasses = [];
18568
18569         this.applyConfig();
18570
18571         this.handleOnAvailable();
18572     },
18573
18574     /**
18575      * Applies the configuration parameters that were passed into the constructor.
18576      * This is supposed to happen at each level through the inheritance chain.  So
18577      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18578      * DragDrop in order to get all of the parameters that are available in
18579      * each object.
18580      * @method applyConfig
18581      */
18582     applyConfig: function() {
18583
18584         // configurable properties:
18585         //    padding, isTarget, maintainOffset, primaryButtonOnly
18586         this.padding           = this.config.padding || [0, 0, 0, 0];
18587         this.isTarget          = (this.config.isTarget !== false);
18588         this.maintainOffset    = (this.config.maintainOffset);
18589         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18590
18591     },
18592
18593     /**
18594      * Executed when the linked element is available
18595      * @method handleOnAvailable
18596      * @private
18597      */
18598     handleOnAvailable: function() {
18599         this.available = true;
18600         this.resetConstraints();
18601         this.onAvailable();
18602     },
18603
18604      /**
18605      * Configures the padding for the target zone in px.  Effectively expands
18606      * (or reduces) the virtual object size for targeting calculations.
18607      * Supports css-style shorthand; if only one parameter is passed, all sides
18608      * will have that padding, and if only two are passed, the top and bottom
18609      * will have the first param, the left and right the second.
18610      * @method setPadding
18611      * @param {int} iTop    Top pad
18612      * @param {int} iRight  Right pad
18613      * @param {int} iBot    Bot pad
18614      * @param {int} iLeft   Left pad
18615      */
18616     setPadding: function(iTop, iRight, iBot, iLeft) {
18617         // this.padding = [iLeft, iRight, iTop, iBot];
18618         if (!iRight && 0 !== iRight) {
18619             this.padding = [iTop, iTop, iTop, iTop];
18620         } else if (!iBot && 0 !== iBot) {
18621             this.padding = [iTop, iRight, iTop, iRight];
18622         } else {
18623             this.padding = [iTop, iRight, iBot, iLeft];
18624         }
18625     },
18626
18627     /**
18628      * Stores the initial placement of the linked element.
18629      * @method setInitialPosition
18630      * @param {int} diffX   the X offset, default 0
18631      * @param {int} diffY   the Y offset, default 0
18632      */
18633     setInitPosition: function(diffX, diffY) {
18634         var el = this.getEl();
18635
18636         if (!this.DDM.verifyEl(el)) {
18637             return;
18638         }
18639
18640         var dx = diffX || 0;
18641         var dy = diffY || 0;
18642
18643         var p = Dom.getXY( el );
18644
18645         this.initPageX = p[0] - dx;
18646         this.initPageY = p[1] - dy;
18647
18648         this.lastPageX = p[0];
18649         this.lastPageY = p[1];
18650
18651
18652         this.setStartPosition(p);
18653     },
18654
18655     /**
18656      * Sets the start position of the element.  This is set when the obj
18657      * is initialized, the reset when a drag is started.
18658      * @method setStartPosition
18659      * @param pos current position (from previous lookup)
18660      * @private
18661      */
18662     setStartPosition: function(pos) {
18663         var p = pos || Dom.getXY( this.getEl() );
18664         this.deltaSetXY = null;
18665
18666         this.startPageX = p[0];
18667         this.startPageY = p[1];
18668     },
18669
18670     /**
18671      * Add this instance to a group of related drag/drop objects.  All
18672      * instances belong to at least one group, and can belong to as many
18673      * groups as needed.
18674      * @method addToGroup
18675      * @param sGroup {string} the name of the group
18676      */
18677     addToGroup: function(sGroup) {
18678         this.groups[sGroup] = true;
18679         this.DDM.regDragDrop(this, sGroup);
18680     },
18681
18682     /**
18683      * Remove's this instance from the supplied interaction group
18684      * @method removeFromGroup
18685      * @param {string}  sGroup  The group to drop
18686      */
18687     removeFromGroup: function(sGroup) {
18688         if (this.groups[sGroup]) {
18689             delete this.groups[sGroup];
18690         }
18691
18692         this.DDM.removeDDFromGroup(this, sGroup);
18693     },
18694
18695     /**
18696      * Allows you to specify that an element other than the linked element
18697      * will be moved with the cursor during a drag
18698      * @method setDragElId
18699      * @param id {string} the id of the element that will be used to initiate the drag
18700      */
18701     setDragElId: function(id) {
18702         this.dragElId = id;
18703     },
18704
18705     /**
18706      * Allows you to specify a child of the linked element that should be
18707      * used to initiate the drag operation.  An example of this would be if
18708      * you have a content div with text and links.  Clicking anywhere in the
18709      * content area would normally start the drag operation.  Use this method
18710      * to specify that an element inside of the content div is the element
18711      * that starts the drag operation.
18712      * @method setHandleElId
18713      * @param id {string} the id of the element that will be used to
18714      * initiate the drag.
18715      */
18716     setHandleElId: function(id) {
18717         if (typeof id !== "string") {
18718             id = Roo.id(id);
18719         }
18720         this.handleElId = id;
18721         this.DDM.regHandle(this.id, id);
18722     },
18723
18724     /**
18725      * Allows you to set an element outside of the linked element as a drag
18726      * handle
18727      * @method setOuterHandleElId
18728      * @param id the id of the element that will be used to initiate the drag
18729      */
18730     setOuterHandleElId: function(id) {
18731         if (typeof id !== "string") {
18732             id = Roo.id(id);
18733         }
18734         Event.on(id, "mousedown",
18735                 this.handleMouseDown, this);
18736         this.setHandleElId(id);
18737
18738         this.hasOuterHandles = true;
18739     },
18740
18741     /**
18742      * Remove all drag and drop hooks for this element
18743      * @method unreg
18744      */
18745     unreg: function() {
18746         Event.un(this.id, "mousedown",
18747                 this.handleMouseDown);
18748         Event.un(this.id, "touchstart",
18749                 this.handleMouseDown);
18750         this._domRef = null;
18751         this.DDM._remove(this);
18752     },
18753
18754     destroy : function(){
18755         this.unreg();
18756     },
18757
18758     /**
18759      * Returns true if this instance is locked, or the drag drop mgr is locked
18760      * (meaning that all drag/drop is disabled on the page.)
18761      * @method isLocked
18762      * @return {boolean} true if this obj or all drag/drop is locked, else
18763      * false
18764      */
18765     isLocked: function() {
18766         return (this.DDM.isLocked() || this.locked);
18767     },
18768
18769     /**
18770      * Fired when this object is clicked
18771      * @method handleMouseDown
18772      * @param {Event} e
18773      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18774      * @private
18775      */
18776     handleMouseDown: function(e, oDD){
18777      
18778         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18779             //Roo.log('not touch/ button !=0');
18780             return;
18781         }
18782         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18783             return; // double touch..
18784         }
18785         
18786
18787         if (this.isLocked()) {
18788             //Roo.log('locked');
18789             return;
18790         }
18791
18792         this.DDM.refreshCache(this.groups);
18793 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18794         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18795         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18796             //Roo.log('no outer handes or not over target');
18797                 // do nothing.
18798         } else {
18799 //            Roo.log('check validator');
18800             if (this.clickValidator(e)) {
18801 //                Roo.log('validate success');
18802                 // set the initial element position
18803                 this.setStartPosition();
18804
18805
18806                 this.b4MouseDown(e);
18807                 this.onMouseDown(e);
18808
18809                 this.DDM.handleMouseDown(e, this);
18810
18811                 this.DDM.stopEvent(e);
18812             } else {
18813
18814
18815             }
18816         }
18817     },
18818
18819     clickValidator: function(e) {
18820         var target = e.getTarget();
18821         return ( this.isValidHandleChild(target) &&
18822                     (this.id == this.handleElId ||
18823                         this.DDM.handleWasClicked(target, this.id)) );
18824     },
18825
18826     /**
18827      * Allows you to specify a tag name that should not start a drag operation
18828      * when clicked.  This is designed to facilitate embedding links within a
18829      * drag handle that do something other than start the drag.
18830      * @method addInvalidHandleType
18831      * @param {string} tagName the type of element to exclude
18832      */
18833     addInvalidHandleType: function(tagName) {
18834         var type = tagName.toUpperCase();
18835         this.invalidHandleTypes[type] = type;
18836     },
18837
18838     /**
18839      * Lets you to specify an element id for a child of a drag handle
18840      * that should not initiate a drag
18841      * @method addInvalidHandleId
18842      * @param {string} id the element id of the element you wish to ignore
18843      */
18844     addInvalidHandleId: function(id) {
18845         if (typeof id !== "string") {
18846             id = Roo.id(id);
18847         }
18848         this.invalidHandleIds[id] = id;
18849     },
18850
18851     /**
18852      * Lets you specify a css class of elements that will not initiate a drag
18853      * @method addInvalidHandleClass
18854      * @param {string} cssClass the class of the elements you wish to ignore
18855      */
18856     addInvalidHandleClass: function(cssClass) {
18857         this.invalidHandleClasses.push(cssClass);
18858     },
18859
18860     /**
18861      * Unsets an excluded tag name set by addInvalidHandleType
18862      * @method removeInvalidHandleType
18863      * @param {string} tagName the type of element to unexclude
18864      */
18865     removeInvalidHandleType: function(tagName) {
18866         var type = tagName.toUpperCase();
18867         // this.invalidHandleTypes[type] = null;
18868         delete this.invalidHandleTypes[type];
18869     },
18870
18871     /**
18872      * Unsets an invalid handle id
18873      * @method removeInvalidHandleId
18874      * @param {string} id the id of the element to re-enable
18875      */
18876     removeInvalidHandleId: function(id) {
18877         if (typeof id !== "string") {
18878             id = Roo.id(id);
18879         }
18880         delete this.invalidHandleIds[id];
18881     },
18882
18883     /**
18884      * Unsets an invalid css class
18885      * @method removeInvalidHandleClass
18886      * @param {string} cssClass the class of the element(s) you wish to
18887      * re-enable
18888      */
18889     removeInvalidHandleClass: function(cssClass) {
18890         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18891             if (this.invalidHandleClasses[i] == cssClass) {
18892                 delete this.invalidHandleClasses[i];
18893             }
18894         }
18895     },
18896
18897     /**
18898      * Checks the tag exclusion list to see if this click should be ignored
18899      * @method isValidHandleChild
18900      * @param {HTMLElement} node the HTMLElement to evaluate
18901      * @return {boolean} true if this is a valid tag type, false if not
18902      */
18903     isValidHandleChild: function(node) {
18904
18905         var valid = true;
18906         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18907         var nodeName;
18908         try {
18909             nodeName = node.nodeName.toUpperCase();
18910         } catch(e) {
18911             nodeName = node.nodeName;
18912         }
18913         valid = valid && !this.invalidHandleTypes[nodeName];
18914         valid = valid && !this.invalidHandleIds[node.id];
18915
18916         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18917             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18918         }
18919
18920
18921         return valid;
18922
18923     },
18924
18925     /**
18926      * Create the array of horizontal tick marks if an interval was specified
18927      * in setXConstraint().
18928      * @method setXTicks
18929      * @private
18930      */
18931     setXTicks: function(iStartX, iTickSize) {
18932         this.xTicks = [];
18933         this.xTickSize = iTickSize;
18934
18935         var tickMap = {};
18936
18937         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18938             if (!tickMap[i]) {
18939                 this.xTicks[this.xTicks.length] = i;
18940                 tickMap[i] = true;
18941             }
18942         }
18943
18944         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18945             if (!tickMap[i]) {
18946                 this.xTicks[this.xTicks.length] = i;
18947                 tickMap[i] = true;
18948             }
18949         }
18950
18951         this.xTicks.sort(this.DDM.numericSort) ;
18952     },
18953
18954     /**
18955      * Create the array of vertical tick marks if an interval was specified in
18956      * setYConstraint().
18957      * @method setYTicks
18958      * @private
18959      */
18960     setYTicks: function(iStartY, iTickSize) {
18961         this.yTicks = [];
18962         this.yTickSize = iTickSize;
18963
18964         var tickMap = {};
18965
18966         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18967             if (!tickMap[i]) {
18968                 this.yTicks[this.yTicks.length] = i;
18969                 tickMap[i] = true;
18970             }
18971         }
18972
18973         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18974             if (!tickMap[i]) {
18975                 this.yTicks[this.yTicks.length] = i;
18976                 tickMap[i] = true;
18977             }
18978         }
18979
18980         this.yTicks.sort(this.DDM.numericSort) ;
18981     },
18982
18983     /**
18984      * By default, the element can be dragged any place on the screen.  Use
18985      * this method to limit the horizontal travel of the element.  Pass in
18986      * 0,0 for the parameters if you want to lock the drag to the y axis.
18987      * @method setXConstraint
18988      * @param {int} iLeft the number of pixels the element can move to the left
18989      * @param {int} iRight the number of pixels the element can move to the
18990      * right
18991      * @param {int} iTickSize optional parameter for specifying that the
18992      * element
18993      * should move iTickSize pixels at a time.
18994      */
18995     setXConstraint: function(iLeft, iRight, iTickSize) {
18996         this.leftConstraint = iLeft;
18997         this.rightConstraint = iRight;
18998
18999         this.minX = this.initPageX - iLeft;
19000         this.maxX = this.initPageX + iRight;
19001         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19002
19003         this.constrainX = true;
19004     },
19005
19006     /**
19007      * Clears any constraints applied to this instance.  Also clears ticks
19008      * since they can't exist independent of a constraint at this time.
19009      * @method clearConstraints
19010      */
19011     clearConstraints: function() {
19012         this.constrainX = false;
19013         this.constrainY = false;
19014         this.clearTicks();
19015     },
19016
19017     /**
19018      * Clears any tick interval defined for this instance
19019      * @method clearTicks
19020      */
19021     clearTicks: function() {
19022         this.xTicks = null;
19023         this.yTicks = null;
19024         this.xTickSize = 0;
19025         this.yTickSize = 0;
19026     },
19027
19028     /**
19029      * By default, the element can be dragged any place on the screen.  Set
19030      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19031      * parameters if you want to lock the drag to the x axis.
19032      * @method setYConstraint
19033      * @param {int} iUp the number of pixels the element can move up
19034      * @param {int} iDown the number of pixels the element can move down
19035      * @param {int} iTickSize optional parameter for specifying that the
19036      * element should move iTickSize pixels at a time.
19037      */
19038     setYConstraint: function(iUp, iDown, iTickSize) {
19039         this.topConstraint = iUp;
19040         this.bottomConstraint = iDown;
19041
19042         this.minY = this.initPageY - iUp;
19043         this.maxY = this.initPageY + iDown;
19044         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19045
19046         this.constrainY = true;
19047
19048     },
19049
19050     /**
19051      * resetConstraints must be called if you manually reposition a dd element.
19052      * @method resetConstraints
19053      * @param {boolean} maintainOffset
19054      */
19055     resetConstraints: function() {
19056
19057
19058         // Maintain offsets if necessary
19059         if (this.initPageX || this.initPageX === 0) {
19060             // figure out how much this thing has moved
19061             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19062             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19063
19064             this.setInitPosition(dx, dy);
19065
19066         // This is the first time we have detected the element's position
19067         } else {
19068             this.setInitPosition();
19069         }
19070
19071         if (this.constrainX) {
19072             this.setXConstraint( this.leftConstraint,
19073                                  this.rightConstraint,
19074                                  this.xTickSize        );
19075         }
19076
19077         if (this.constrainY) {
19078             this.setYConstraint( this.topConstraint,
19079                                  this.bottomConstraint,
19080                                  this.yTickSize         );
19081         }
19082     },
19083
19084     /**
19085      * Normally the drag element is moved pixel by pixel, but we can specify
19086      * that it move a number of pixels at a time.  This method resolves the
19087      * location when we have it set up like this.
19088      * @method getTick
19089      * @param {int} val where we want to place the object
19090      * @param {int[]} tickArray sorted array of valid points
19091      * @return {int} the closest tick
19092      * @private
19093      */
19094     getTick: function(val, tickArray) {
19095
19096         if (!tickArray) {
19097             // If tick interval is not defined, it is effectively 1 pixel,
19098             // so we return the value passed to us.
19099             return val;
19100         } else if (tickArray[0] >= val) {
19101             // The value is lower than the first tick, so we return the first
19102             // tick.
19103             return tickArray[0];
19104         } else {
19105             for (var i=0, len=tickArray.length; i<len; ++i) {
19106                 var next = i + 1;
19107                 if (tickArray[next] && tickArray[next] >= val) {
19108                     var diff1 = val - tickArray[i];
19109                     var diff2 = tickArray[next] - val;
19110                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19111                 }
19112             }
19113
19114             // The value is larger than the last tick, so we return the last
19115             // tick.
19116             return tickArray[tickArray.length - 1];
19117         }
19118     },
19119
19120     /**
19121      * toString method
19122      * @method toString
19123      * @return {string} string representation of the dd obj
19124      */
19125     toString: function() {
19126         return ("DragDrop " + this.id);
19127     }
19128
19129 });
19130
19131 })();
19132 /*
19133  * Based on:
19134  * Ext JS Library 1.1.1
19135  * Copyright(c) 2006-2007, Ext JS, LLC.
19136  *
19137  * Originally Released Under LGPL - original licence link has changed is not relivant.
19138  *
19139  * Fork - LGPL
19140  * <script type="text/javascript">
19141  */
19142
19143
19144 /**
19145  * The drag and drop utility provides a framework for building drag and drop
19146  * applications.  In addition to enabling drag and drop for specific elements,
19147  * the drag and drop elements are tracked by the manager class, and the
19148  * interactions between the various elements are tracked during the drag and
19149  * the implementing code is notified about these important moments.
19150  */
19151
19152 // Only load the library once.  Rewriting the manager class would orphan
19153 // existing drag and drop instances.
19154 if (!Roo.dd.DragDropMgr) {
19155
19156 /**
19157  * @class Roo.dd.DragDropMgr
19158  * DragDropMgr is a singleton that tracks the element interaction for
19159  * all DragDrop items in the window.  Generally, you will not call
19160  * this class directly, but it does have helper methods that could
19161  * be useful in your DragDrop implementations.
19162  * @singleton
19163  */
19164 Roo.dd.DragDropMgr = function() {
19165
19166     var Event = Roo.EventManager;
19167
19168     return {
19169
19170         /**
19171          * Two dimensional Array of registered DragDrop objects.  The first
19172          * dimension is the DragDrop item group, the second the DragDrop
19173          * object.
19174          * @property ids
19175          * @type {string: string}
19176          * @private
19177          * @static
19178          */
19179         ids: {},
19180
19181         /**
19182          * Array of element ids defined as drag handles.  Used to determine
19183          * if the element that generated the mousedown event is actually the
19184          * handle and not the html element itself.
19185          * @property handleIds
19186          * @type {string: string}
19187          * @private
19188          * @static
19189          */
19190         handleIds: {},
19191
19192         /**
19193          * the DragDrop object that is currently being dragged
19194          * @property dragCurrent
19195          * @type DragDrop
19196          * @private
19197          * @static
19198          **/
19199         dragCurrent: null,
19200
19201         /**
19202          * the DragDrop object(s) that are being hovered over
19203          * @property dragOvers
19204          * @type Array
19205          * @private
19206          * @static
19207          */
19208         dragOvers: {},
19209
19210         /**
19211          * the X distance between the cursor and the object being dragged
19212          * @property deltaX
19213          * @type int
19214          * @private
19215          * @static
19216          */
19217         deltaX: 0,
19218
19219         /**
19220          * the Y distance between the cursor and the object being dragged
19221          * @property deltaY
19222          * @type int
19223          * @private
19224          * @static
19225          */
19226         deltaY: 0,
19227
19228         /**
19229          * Flag to determine if we should prevent the default behavior of the
19230          * events we define. By default this is true, but this can be set to
19231          * false if you need the default behavior (not recommended)
19232          * @property preventDefault
19233          * @type boolean
19234          * @static
19235          */
19236         preventDefault: true,
19237
19238         /**
19239          * Flag to determine if we should stop the propagation of the events
19240          * we generate. This is true by default but you may want to set it to
19241          * false if the html element contains other features that require the
19242          * mouse click.
19243          * @property stopPropagation
19244          * @type boolean
19245          * @static
19246          */
19247         stopPropagation: true,
19248
19249         /**
19250          * Internal flag that is set to true when drag and drop has been
19251          * intialized
19252          * @property initialized
19253          * @private
19254          * @static
19255          */
19256         initalized: false,
19257
19258         /**
19259          * All drag and drop can be disabled.
19260          * @property locked
19261          * @private
19262          * @static
19263          */
19264         locked: false,
19265
19266         /**
19267          * Called the first time an element is registered.
19268          * @method init
19269          * @private
19270          * @static
19271          */
19272         init: function() {
19273             this.initialized = true;
19274         },
19275
19276         /**
19277          * In point mode, drag and drop interaction is defined by the
19278          * location of the cursor during the drag/drop
19279          * @property POINT
19280          * @type int
19281          * @static
19282          */
19283         POINT: 0,
19284
19285         /**
19286          * In intersect mode, drag and drop interactio nis defined by the
19287          * overlap of two or more drag and drop objects.
19288          * @property INTERSECT
19289          * @type int
19290          * @static
19291          */
19292         INTERSECT: 1,
19293
19294         /**
19295          * The current drag and drop mode.  Default: POINT
19296          * @property mode
19297          * @type int
19298          * @static
19299          */
19300         mode: 0,
19301
19302         /**
19303          * Runs method on all drag and drop objects
19304          * @method _execOnAll
19305          * @private
19306          * @static
19307          */
19308         _execOnAll: function(sMethod, args) {
19309             for (var i in this.ids) {
19310                 for (var j in this.ids[i]) {
19311                     var oDD = this.ids[i][j];
19312                     if (! this.isTypeOfDD(oDD)) {
19313                         continue;
19314                     }
19315                     oDD[sMethod].apply(oDD, args);
19316                 }
19317             }
19318         },
19319
19320         /**
19321          * Drag and drop initialization.  Sets up the global event handlers
19322          * @method _onLoad
19323          * @private
19324          * @static
19325          */
19326         _onLoad: function() {
19327
19328             this.init();
19329
19330             if (!Roo.isTouch) {
19331                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19332                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19333             }
19334             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19335             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19336             
19337             Event.on(window,   "unload",    this._onUnload, this, true);
19338             Event.on(window,   "resize",    this._onResize, this, true);
19339             // Event.on(window,   "mouseout",    this._test);
19340
19341         },
19342
19343         /**
19344          * Reset constraints on all drag and drop objs
19345          * @method _onResize
19346          * @private
19347          * @static
19348          */
19349         _onResize: function(e) {
19350             this._execOnAll("resetConstraints", []);
19351         },
19352
19353         /**
19354          * Lock all drag and drop functionality
19355          * @method lock
19356          * @static
19357          */
19358         lock: function() { this.locked = true; },
19359
19360         /**
19361          * Unlock all drag and drop functionality
19362          * @method unlock
19363          * @static
19364          */
19365         unlock: function() { this.locked = false; },
19366
19367         /**
19368          * Is drag and drop locked?
19369          * @method isLocked
19370          * @return {boolean} True if drag and drop is locked, false otherwise.
19371          * @static
19372          */
19373         isLocked: function() { return this.locked; },
19374
19375         /**
19376          * Location cache that is set for all drag drop objects when a drag is
19377          * initiated, cleared when the drag is finished.
19378          * @property locationCache
19379          * @private
19380          * @static
19381          */
19382         locationCache: {},
19383
19384         /**
19385          * Set useCache to false if you want to force object the lookup of each
19386          * drag and drop linked element constantly during a drag.
19387          * @property useCache
19388          * @type boolean
19389          * @static
19390          */
19391         useCache: true,
19392
19393         /**
19394          * The number of pixels that the mouse needs to move after the
19395          * mousedown before the drag is initiated.  Default=3;
19396          * @property clickPixelThresh
19397          * @type int
19398          * @static
19399          */
19400         clickPixelThresh: 3,
19401
19402         /**
19403          * The number of milliseconds after the mousedown event to initiate the
19404          * drag if we don't get a mouseup event. Default=1000
19405          * @property clickTimeThresh
19406          * @type int
19407          * @static
19408          */
19409         clickTimeThresh: 350,
19410
19411         /**
19412          * Flag that indicates that either the drag pixel threshold or the
19413          * mousdown time threshold has been met
19414          * @property dragThreshMet
19415          * @type boolean
19416          * @private
19417          * @static
19418          */
19419         dragThreshMet: false,
19420
19421         /**
19422          * Timeout used for the click time threshold
19423          * @property clickTimeout
19424          * @type Object
19425          * @private
19426          * @static
19427          */
19428         clickTimeout: null,
19429
19430         /**
19431          * The X position of the mousedown event stored for later use when a
19432          * drag threshold is met.
19433          * @property startX
19434          * @type int
19435          * @private
19436          * @static
19437          */
19438         startX: 0,
19439
19440         /**
19441          * The Y position of the mousedown event stored for later use when a
19442          * drag threshold is met.
19443          * @property startY
19444          * @type int
19445          * @private
19446          * @static
19447          */
19448         startY: 0,
19449
19450         /**
19451          * Each DragDrop instance must be registered with the DragDropMgr.
19452          * This is executed in DragDrop.init()
19453          * @method regDragDrop
19454          * @param {DragDrop} oDD the DragDrop object to register
19455          * @param {String} sGroup the name of the group this element belongs to
19456          * @static
19457          */
19458         regDragDrop: function(oDD, sGroup) {
19459             if (!this.initialized) { this.init(); }
19460
19461             if (!this.ids[sGroup]) {
19462                 this.ids[sGroup] = {};
19463             }
19464             this.ids[sGroup][oDD.id] = oDD;
19465         },
19466
19467         /**
19468          * Removes the supplied dd instance from the supplied group. Executed
19469          * by DragDrop.removeFromGroup, so don't call this function directly.
19470          * @method removeDDFromGroup
19471          * @private
19472          * @static
19473          */
19474         removeDDFromGroup: function(oDD, sGroup) {
19475             if (!this.ids[sGroup]) {
19476                 this.ids[sGroup] = {};
19477             }
19478
19479             var obj = this.ids[sGroup];
19480             if (obj && obj[oDD.id]) {
19481                 delete obj[oDD.id];
19482             }
19483         },
19484
19485         /**
19486          * Unregisters a drag and drop item.  This is executed in
19487          * DragDrop.unreg, use that method instead of calling this directly.
19488          * @method _remove
19489          * @private
19490          * @static
19491          */
19492         _remove: function(oDD) {
19493             for (var g in oDD.groups) {
19494                 if (g && this.ids[g][oDD.id]) {
19495                     delete this.ids[g][oDD.id];
19496                 }
19497             }
19498             delete this.handleIds[oDD.id];
19499         },
19500
19501         /**
19502          * Each DragDrop handle element must be registered.  This is done
19503          * automatically when executing DragDrop.setHandleElId()
19504          * @method regHandle
19505          * @param {String} sDDId the DragDrop id this element is a handle for
19506          * @param {String} sHandleId the id of the element that is the drag
19507          * handle
19508          * @static
19509          */
19510         regHandle: function(sDDId, sHandleId) {
19511             if (!this.handleIds[sDDId]) {
19512                 this.handleIds[sDDId] = {};
19513             }
19514             this.handleIds[sDDId][sHandleId] = sHandleId;
19515         },
19516
19517         /**
19518          * Utility function to determine if a given element has been
19519          * registered as a drag drop item.
19520          * @method isDragDrop
19521          * @param {String} id the element id to check
19522          * @return {boolean} true if this element is a DragDrop item,
19523          * false otherwise
19524          * @static
19525          */
19526         isDragDrop: function(id) {
19527             return ( this.getDDById(id) ) ? true : false;
19528         },
19529
19530         /**
19531          * Returns the drag and drop instances that are in all groups the
19532          * passed in instance belongs to.
19533          * @method getRelated
19534          * @param {DragDrop} p_oDD the obj to get related data for
19535          * @param {boolean} bTargetsOnly if true, only return targetable objs
19536          * @return {DragDrop[]} the related instances
19537          * @static
19538          */
19539         getRelated: function(p_oDD, bTargetsOnly) {
19540             var oDDs = [];
19541             for (var i in p_oDD.groups) {
19542                 for (j in this.ids[i]) {
19543                     var dd = this.ids[i][j];
19544                     if (! this.isTypeOfDD(dd)) {
19545                         continue;
19546                     }
19547                     if (!bTargetsOnly || dd.isTarget) {
19548                         oDDs[oDDs.length] = dd;
19549                     }
19550                 }
19551             }
19552
19553             return oDDs;
19554         },
19555
19556         /**
19557          * Returns true if the specified dd target is a legal target for
19558          * the specifice drag obj
19559          * @method isLegalTarget
19560          * @param {DragDrop} the drag obj
19561          * @param {DragDrop} the target
19562          * @return {boolean} true if the target is a legal target for the
19563          * dd obj
19564          * @static
19565          */
19566         isLegalTarget: function (oDD, oTargetDD) {
19567             var targets = this.getRelated(oDD, true);
19568             for (var i=0, len=targets.length;i<len;++i) {
19569                 if (targets[i].id == oTargetDD.id) {
19570                     return true;
19571                 }
19572             }
19573
19574             return false;
19575         },
19576
19577         /**
19578          * My goal is to be able to transparently determine if an object is
19579          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19580          * returns "object", oDD.constructor.toString() always returns
19581          * "DragDrop" and not the name of the subclass.  So for now it just
19582          * evaluates a well-known variable in DragDrop.
19583          * @method isTypeOfDD
19584          * @param {Object} the object to evaluate
19585          * @return {boolean} true if typeof oDD = DragDrop
19586          * @static
19587          */
19588         isTypeOfDD: function (oDD) {
19589             return (oDD && oDD.__ygDragDrop);
19590         },
19591
19592         /**
19593          * Utility function to determine if a given element has been
19594          * registered as a drag drop handle for the given Drag Drop object.
19595          * @method isHandle
19596          * @param {String} id the element id to check
19597          * @return {boolean} true if this element is a DragDrop handle, false
19598          * otherwise
19599          * @static
19600          */
19601         isHandle: function(sDDId, sHandleId) {
19602             return ( this.handleIds[sDDId] &&
19603                             this.handleIds[sDDId][sHandleId] );
19604         },
19605
19606         /**
19607          * Returns the DragDrop instance for a given id
19608          * @method getDDById
19609          * @param {String} id the id of the DragDrop object
19610          * @return {DragDrop} the drag drop object, null if it is not found
19611          * @static
19612          */
19613         getDDById: function(id) {
19614             for (var i in this.ids) {
19615                 if (this.ids[i][id]) {
19616                     return this.ids[i][id];
19617                 }
19618             }
19619             return null;
19620         },
19621
19622         /**
19623          * Fired after a registered DragDrop object gets the mousedown event.
19624          * Sets up the events required to track the object being dragged
19625          * @method handleMouseDown
19626          * @param {Event} e the event
19627          * @param oDD the DragDrop object being dragged
19628          * @private
19629          * @static
19630          */
19631         handleMouseDown: function(e, oDD) {
19632             if(Roo.QuickTips){
19633                 Roo.QuickTips.disable();
19634             }
19635             this.currentTarget = e.getTarget();
19636
19637             this.dragCurrent = oDD;
19638
19639             var el = oDD.getEl();
19640
19641             // track start position
19642             this.startX = e.getPageX();
19643             this.startY = e.getPageY();
19644
19645             this.deltaX = this.startX - el.offsetLeft;
19646             this.deltaY = this.startY - el.offsetTop;
19647
19648             this.dragThreshMet = false;
19649
19650             this.clickTimeout = setTimeout(
19651                     function() {
19652                         var DDM = Roo.dd.DDM;
19653                         DDM.startDrag(DDM.startX, DDM.startY);
19654                     },
19655                     this.clickTimeThresh );
19656         },
19657
19658         /**
19659          * Fired when either the drag pixel threshol or the mousedown hold
19660          * time threshold has been met.
19661          * @method startDrag
19662          * @param x {int} the X position of the original mousedown
19663          * @param y {int} the Y position of the original mousedown
19664          * @static
19665          */
19666         startDrag: function(x, y) {
19667             clearTimeout(this.clickTimeout);
19668             if (this.dragCurrent) {
19669                 this.dragCurrent.b4StartDrag(x, y);
19670                 this.dragCurrent.startDrag(x, y);
19671             }
19672             this.dragThreshMet = true;
19673         },
19674
19675         /**
19676          * Internal function to handle the mouseup event.  Will be invoked
19677          * from the context of the document.
19678          * @method handleMouseUp
19679          * @param {Event} e the event
19680          * @private
19681          * @static
19682          */
19683         handleMouseUp: function(e) {
19684
19685             if(Roo.QuickTips){
19686                 Roo.QuickTips.enable();
19687             }
19688             if (! this.dragCurrent) {
19689                 return;
19690             }
19691
19692             clearTimeout(this.clickTimeout);
19693
19694             if (this.dragThreshMet) {
19695                 this.fireEvents(e, true);
19696             } else {
19697             }
19698
19699             this.stopDrag(e);
19700
19701             this.stopEvent(e);
19702         },
19703
19704         /**
19705          * Utility to stop event propagation and event default, if these
19706          * features are turned on.
19707          * @method stopEvent
19708          * @param {Event} e the event as returned by this.getEvent()
19709          * @static
19710          */
19711         stopEvent: function(e){
19712             if(this.stopPropagation) {
19713                 e.stopPropagation();
19714             }
19715
19716             if (this.preventDefault) {
19717                 e.preventDefault();
19718             }
19719         },
19720
19721         /**
19722          * Internal function to clean up event handlers after the drag
19723          * operation is complete
19724          * @method stopDrag
19725          * @param {Event} e the event
19726          * @private
19727          * @static
19728          */
19729         stopDrag: function(e) {
19730             // Fire the drag end event for the item that was dragged
19731             if (this.dragCurrent) {
19732                 if (this.dragThreshMet) {
19733                     this.dragCurrent.b4EndDrag(e);
19734                     this.dragCurrent.endDrag(e);
19735                 }
19736
19737                 this.dragCurrent.onMouseUp(e);
19738             }
19739
19740             this.dragCurrent = null;
19741             this.dragOvers = {};
19742         },
19743
19744         /**
19745          * Internal function to handle the mousemove event.  Will be invoked
19746          * from the context of the html element.
19747          *
19748          * @TODO figure out what we can do about mouse events lost when the
19749          * user drags objects beyond the window boundary.  Currently we can
19750          * detect this in internet explorer by verifying that the mouse is
19751          * down during the mousemove event.  Firefox doesn't give us the
19752          * button state on the mousemove event.
19753          * @method handleMouseMove
19754          * @param {Event} e the event
19755          * @private
19756          * @static
19757          */
19758         handleMouseMove: function(e) {
19759             if (! this.dragCurrent) {
19760                 return true;
19761             }
19762
19763             // var button = e.which || e.button;
19764
19765             // check for IE mouseup outside of page boundary
19766             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19767                 this.stopEvent(e);
19768                 return this.handleMouseUp(e);
19769             }
19770
19771             if (!this.dragThreshMet) {
19772                 var diffX = Math.abs(this.startX - e.getPageX());
19773                 var diffY = Math.abs(this.startY - e.getPageY());
19774                 if (diffX > this.clickPixelThresh ||
19775                             diffY > this.clickPixelThresh) {
19776                     this.startDrag(this.startX, this.startY);
19777                 }
19778             }
19779
19780             if (this.dragThreshMet) {
19781                 this.dragCurrent.b4Drag(e);
19782                 this.dragCurrent.onDrag(e);
19783                 if(!this.dragCurrent.moveOnly){
19784                     this.fireEvents(e, false);
19785                 }
19786             }
19787
19788             this.stopEvent(e);
19789
19790             return true;
19791         },
19792
19793         /**
19794          * Iterates over all of the DragDrop elements to find ones we are
19795          * hovering over or dropping on
19796          * @method fireEvents
19797          * @param {Event} e the event
19798          * @param {boolean} isDrop is this a drop op or a mouseover op?
19799          * @private
19800          * @static
19801          */
19802         fireEvents: function(e, isDrop) {
19803             var dc = this.dragCurrent;
19804
19805             // If the user did the mouse up outside of the window, we could
19806             // get here even though we have ended the drag.
19807             if (!dc || dc.isLocked()) {
19808                 return;
19809             }
19810
19811             var pt = e.getPoint();
19812
19813             // cache the previous dragOver array
19814             var oldOvers = [];
19815
19816             var outEvts   = [];
19817             var overEvts  = [];
19818             var dropEvts  = [];
19819             var enterEvts = [];
19820
19821             // Check to see if the object(s) we were hovering over is no longer
19822             // being hovered over so we can fire the onDragOut event
19823             for (var i in this.dragOvers) {
19824
19825                 var ddo = this.dragOvers[i];
19826
19827                 if (! this.isTypeOfDD(ddo)) {
19828                     continue;
19829                 }
19830
19831                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19832                     outEvts.push( ddo );
19833                 }
19834
19835                 oldOvers[i] = true;
19836                 delete this.dragOvers[i];
19837             }
19838
19839             for (var sGroup in dc.groups) {
19840
19841                 if ("string" != typeof sGroup) {
19842                     continue;
19843                 }
19844
19845                 for (i in this.ids[sGroup]) {
19846                     var oDD = this.ids[sGroup][i];
19847                     if (! this.isTypeOfDD(oDD)) {
19848                         continue;
19849                     }
19850
19851                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19852                         if (this.isOverTarget(pt, oDD, this.mode)) {
19853                             // look for drop interactions
19854                             if (isDrop) {
19855                                 dropEvts.push( oDD );
19856                             // look for drag enter and drag over interactions
19857                             } else {
19858
19859                                 // initial drag over: dragEnter fires
19860                                 if (!oldOvers[oDD.id]) {
19861                                     enterEvts.push( oDD );
19862                                 // subsequent drag overs: dragOver fires
19863                                 } else {
19864                                     overEvts.push( oDD );
19865                                 }
19866
19867                                 this.dragOvers[oDD.id] = oDD;
19868                             }
19869                         }
19870                     }
19871                 }
19872             }
19873
19874             if (this.mode) {
19875                 if (outEvts.length) {
19876                     dc.b4DragOut(e, outEvts);
19877                     dc.onDragOut(e, outEvts);
19878                 }
19879
19880                 if (enterEvts.length) {
19881                     dc.onDragEnter(e, enterEvts);
19882                 }
19883
19884                 if (overEvts.length) {
19885                     dc.b4DragOver(e, overEvts);
19886                     dc.onDragOver(e, overEvts);
19887                 }
19888
19889                 if (dropEvts.length) {
19890                     dc.b4DragDrop(e, dropEvts);
19891                     dc.onDragDrop(e, dropEvts);
19892                 }
19893
19894             } else {
19895                 // fire dragout events
19896                 var len = 0;
19897                 for (i=0, len=outEvts.length; i<len; ++i) {
19898                     dc.b4DragOut(e, outEvts[i].id);
19899                     dc.onDragOut(e, outEvts[i].id);
19900                 }
19901
19902                 // fire enter events
19903                 for (i=0,len=enterEvts.length; i<len; ++i) {
19904                     // dc.b4DragEnter(e, oDD.id);
19905                     dc.onDragEnter(e, enterEvts[i].id);
19906                 }
19907
19908                 // fire over events
19909                 for (i=0,len=overEvts.length; i<len; ++i) {
19910                     dc.b4DragOver(e, overEvts[i].id);
19911                     dc.onDragOver(e, overEvts[i].id);
19912                 }
19913
19914                 // fire drop events
19915                 for (i=0, len=dropEvts.length; i<len; ++i) {
19916                     dc.b4DragDrop(e, dropEvts[i].id);
19917                     dc.onDragDrop(e, dropEvts[i].id);
19918                 }
19919
19920             }
19921
19922             // notify about a drop that did not find a target
19923             if (isDrop && !dropEvts.length) {
19924                 dc.onInvalidDrop(e);
19925             }
19926
19927         },
19928
19929         /**
19930          * Helper function for getting the best match from the list of drag
19931          * and drop objects returned by the drag and drop events when we are
19932          * in INTERSECT mode.  It returns either the first object that the
19933          * cursor is over, or the object that has the greatest overlap with
19934          * the dragged element.
19935          * @method getBestMatch
19936          * @param  {DragDrop[]} dds The array of drag and drop objects
19937          * targeted
19938          * @return {DragDrop}       The best single match
19939          * @static
19940          */
19941         getBestMatch: function(dds) {
19942             var winner = null;
19943             // Return null if the input is not what we expect
19944             //if (!dds || !dds.length || dds.length == 0) {
19945                // winner = null;
19946             // If there is only one item, it wins
19947             //} else if (dds.length == 1) {
19948
19949             var len = dds.length;
19950
19951             if (len == 1) {
19952                 winner = dds[0];
19953             } else {
19954                 // Loop through the targeted items
19955                 for (var i=0; i<len; ++i) {
19956                     var dd = dds[i];
19957                     // If the cursor is over the object, it wins.  If the
19958                     // cursor is over multiple matches, the first one we come
19959                     // to wins.
19960                     if (dd.cursorIsOver) {
19961                         winner = dd;
19962                         break;
19963                     // Otherwise the object with the most overlap wins
19964                     } else {
19965                         if (!winner ||
19966                             winner.overlap.getArea() < dd.overlap.getArea()) {
19967                             winner = dd;
19968                         }
19969                     }
19970                 }
19971             }
19972
19973             return winner;
19974         },
19975
19976         /**
19977          * Refreshes the cache of the top-left and bottom-right points of the
19978          * drag and drop objects in the specified group(s).  This is in the
19979          * format that is stored in the drag and drop instance, so typical
19980          * usage is:
19981          * <code>
19982          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19983          * </code>
19984          * Alternatively:
19985          * <code>
19986          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19987          * </code>
19988          * @TODO this really should be an indexed array.  Alternatively this
19989          * method could accept both.
19990          * @method refreshCache
19991          * @param {Object} groups an associative array of groups to refresh
19992          * @static
19993          */
19994         refreshCache: function(groups) {
19995             for (var sGroup in groups) {
19996                 if ("string" != typeof sGroup) {
19997                     continue;
19998                 }
19999                 for (var i in this.ids[sGroup]) {
20000                     var oDD = this.ids[sGroup][i];
20001
20002                     if (this.isTypeOfDD(oDD)) {
20003                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20004                         var loc = this.getLocation(oDD);
20005                         if (loc) {
20006                             this.locationCache[oDD.id] = loc;
20007                         } else {
20008                             delete this.locationCache[oDD.id];
20009                             // this will unregister the drag and drop object if
20010                             // the element is not in a usable state
20011                             // oDD.unreg();
20012                         }
20013                     }
20014                 }
20015             }
20016         },
20017
20018         /**
20019          * This checks to make sure an element exists and is in the DOM.  The
20020          * main purpose is to handle cases where innerHTML is used to remove
20021          * drag and drop objects from the DOM.  IE provides an 'unspecified
20022          * error' when trying to access the offsetParent of such an element
20023          * @method verifyEl
20024          * @param {HTMLElement} el the element to check
20025          * @return {boolean} true if the element looks usable
20026          * @static
20027          */
20028         verifyEl: function(el) {
20029             if (el) {
20030                 var parent;
20031                 if(Roo.isIE){
20032                     try{
20033                         parent = el.offsetParent;
20034                     }catch(e){}
20035                 }else{
20036                     parent = el.offsetParent;
20037                 }
20038                 if (parent) {
20039                     return true;
20040                 }
20041             }
20042
20043             return false;
20044         },
20045
20046         /**
20047          * Returns a Region object containing the drag and drop element's position
20048          * and size, including the padding configured for it
20049          * @method getLocation
20050          * @param {DragDrop} oDD the drag and drop object to get the
20051          *                       location for
20052          * @return {Roo.lib.Region} a Region object representing the total area
20053          *                             the element occupies, including any padding
20054          *                             the instance is configured for.
20055          * @static
20056          */
20057         getLocation: function(oDD) {
20058             if (! this.isTypeOfDD(oDD)) {
20059                 return null;
20060             }
20061
20062             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20063
20064             try {
20065                 pos= Roo.lib.Dom.getXY(el);
20066             } catch (e) { }
20067
20068             if (!pos) {
20069                 return null;
20070             }
20071
20072             x1 = pos[0];
20073             x2 = x1 + el.offsetWidth;
20074             y1 = pos[1];
20075             y2 = y1 + el.offsetHeight;
20076
20077             t = y1 - oDD.padding[0];
20078             r = x2 + oDD.padding[1];
20079             b = y2 + oDD.padding[2];
20080             l = x1 - oDD.padding[3];
20081
20082             return new Roo.lib.Region( t, r, b, l );
20083         },
20084
20085         /**
20086          * Checks the cursor location to see if it over the target
20087          * @method isOverTarget
20088          * @param {Roo.lib.Point} pt The point to evaluate
20089          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20090          * @return {boolean} true if the mouse is over the target
20091          * @private
20092          * @static
20093          */
20094         isOverTarget: function(pt, oTarget, intersect) {
20095             // use cache if available
20096             var loc = this.locationCache[oTarget.id];
20097             if (!loc || !this.useCache) {
20098                 loc = this.getLocation(oTarget);
20099                 this.locationCache[oTarget.id] = loc;
20100
20101             }
20102
20103             if (!loc) {
20104                 return false;
20105             }
20106
20107             oTarget.cursorIsOver = loc.contains( pt );
20108
20109             // DragDrop is using this as a sanity check for the initial mousedown
20110             // in this case we are done.  In POINT mode, if the drag obj has no
20111             // contraints, we are also done. Otherwise we need to evaluate the
20112             // location of the target as related to the actual location of the
20113             // dragged element.
20114             var dc = this.dragCurrent;
20115             if (!dc || !dc.getTargetCoord ||
20116                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20117                 return oTarget.cursorIsOver;
20118             }
20119
20120             oTarget.overlap = null;
20121
20122             // Get the current location of the drag element, this is the
20123             // location of the mouse event less the delta that represents
20124             // where the original mousedown happened on the element.  We
20125             // need to consider constraints and ticks as well.
20126             var pos = dc.getTargetCoord(pt.x, pt.y);
20127
20128             var el = dc.getDragEl();
20129             var curRegion = new Roo.lib.Region( pos.y,
20130                                                    pos.x + el.offsetWidth,
20131                                                    pos.y + el.offsetHeight,
20132                                                    pos.x );
20133
20134             var overlap = curRegion.intersect(loc);
20135
20136             if (overlap) {
20137                 oTarget.overlap = overlap;
20138                 return (intersect) ? true : oTarget.cursorIsOver;
20139             } else {
20140                 return false;
20141             }
20142         },
20143
20144         /**
20145          * unload event handler
20146          * @method _onUnload
20147          * @private
20148          * @static
20149          */
20150         _onUnload: function(e, me) {
20151             Roo.dd.DragDropMgr.unregAll();
20152         },
20153
20154         /**
20155          * Cleans up the drag and drop events and objects.
20156          * @method unregAll
20157          * @private
20158          * @static
20159          */
20160         unregAll: function() {
20161
20162             if (this.dragCurrent) {
20163                 this.stopDrag();
20164                 this.dragCurrent = null;
20165             }
20166
20167             this._execOnAll("unreg", []);
20168
20169             for (i in this.elementCache) {
20170                 delete this.elementCache[i];
20171             }
20172
20173             this.elementCache = {};
20174             this.ids = {};
20175         },
20176
20177         /**
20178          * A cache of DOM elements
20179          * @property elementCache
20180          * @private
20181          * @static
20182          */
20183         elementCache: {},
20184
20185         /**
20186          * Get the wrapper for the DOM element specified
20187          * @method getElWrapper
20188          * @param {String} id the id of the element to get
20189          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20190          * @private
20191          * @deprecated This wrapper isn't that useful
20192          * @static
20193          */
20194         getElWrapper: function(id) {
20195             var oWrapper = this.elementCache[id];
20196             if (!oWrapper || !oWrapper.el) {
20197                 oWrapper = this.elementCache[id] =
20198                     new this.ElementWrapper(Roo.getDom(id));
20199             }
20200             return oWrapper;
20201         },
20202
20203         /**
20204          * Returns the actual DOM element
20205          * @method getElement
20206          * @param {String} id the id of the elment to get
20207          * @return {Object} The element
20208          * @deprecated use Roo.getDom instead
20209          * @static
20210          */
20211         getElement: function(id) {
20212             return Roo.getDom(id);
20213         },
20214
20215         /**
20216          * Returns the style property for the DOM element (i.e.,
20217          * document.getElById(id).style)
20218          * @method getCss
20219          * @param {String} id the id of the elment to get
20220          * @return {Object} The style property of the element
20221          * @deprecated use Roo.getDom instead
20222          * @static
20223          */
20224         getCss: function(id) {
20225             var el = Roo.getDom(id);
20226             return (el) ? el.style : null;
20227         },
20228
20229         /**
20230          * Inner class for cached elements
20231          * @class DragDropMgr.ElementWrapper
20232          * @for DragDropMgr
20233          * @private
20234          * @deprecated
20235          */
20236         ElementWrapper: function(el) {
20237                 /**
20238                  * The element
20239                  * @property el
20240                  */
20241                 this.el = el || null;
20242                 /**
20243                  * The element id
20244                  * @property id
20245                  */
20246                 this.id = this.el && el.id;
20247                 /**
20248                  * A reference to the style property
20249                  * @property css
20250                  */
20251                 this.css = this.el && el.style;
20252             },
20253
20254         /**
20255          * Returns the X position of an html element
20256          * @method getPosX
20257          * @param el the element for which to get the position
20258          * @return {int} the X coordinate
20259          * @for DragDropMgr
20260          * @deprecated use Roo.lib.Dom.getX instead
20261          * @static
20262          */
20263         getPosX: function(el) {
20264             return Roo.lib.Dom.getX(el);
20265         },
20266
20267         /**
20268          * Returns the Y position of an html element
20269          * @method getPosY
20270          * @param el the element for which to get the position
20271          * @return {int} the Y coordinate
20272          * @deprecated use Roo.lib.Dom.getY instead
20273          * @static
20274          */
20275         getPosY: function(el) {
20276             return Roo.lib.Dom.getY(el);
20277         },
20278
20279         /**
20280          * Swap two nodes.  In IE, we use the native method, for others we
20281          * emulate the IE behavior
20282          * @method swapNode
20283          * @param n1 the first node to swap
20284          * @param n2 the other node to swap
20285          * @static
20286          */
20287         swapNode: function(n1, n2) {
20288             if (n1.swapNode) {
20289                 n1.swapNode(n2);
20290             } else {
20291                 var p = n2.parentNode;
20292                 var s = n2.nextSibling;
20293
20294                 if (s == n1) {
20295                     p.insertBefore(n1, n2);
20296                 } else if (n2 == n1.nextSibling) {
20297                     p.insertBefore(n2, n1);
20298                 } else {
20299                     n1.parentNode.replaceChild(n2, n1);
20300                     p.insertBefore(n1, s);
20301                 }
20302             }
20303         },
20304
20305         /**
20306          * Returns the current scroll position
20307          * @method getScroll
20308          * @private
20309          * @static
20310          */
20311         getScroll: function () {
20312             var t, l, dde=document.documentElement, db=document.body;
20313             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20314                 t = dde.scrollTop;
20315                 l = dde.scrollLeft;
20316             } else if (db) {
20317                 t = db.scrollTop;
20318                 l = db.scrollLeft;
20319             } else {
20320
20321             }
20322             return { top: t, left: l };
20323         },
20324
20325         /**
20326          * Returns the specified element style property
20327          * @method getStyle
20328          * @param {HTMLElement} el          the element
20329          * @param {string}      styleProp   the style property
20330          * @return {string} The value of the style property
20331          * @deprecated use Roo.lib.Dom.getStyle
20332          * @static
20333          */
20334         getStyle: function(el, styleProp) {
20335             return Roo.fly(el).getStyle(styleProp);
20336         },
20337
20338         /**
20339          * Gets the scrollTop
20340          * @method getScrollTop
20341          * @return {int} the document's scrollTop
20342          * @static
20343          */
20344         getScrollTop: function () { return this.getScroll().top; },
20345
20346         /**
20347          * Gets the scrollLeft
20348          * @method getScrollLeft
20349          * @return {int} the document's scrollTop
20350          * @static
20351          */
20352         getScrollLeft: function () { return this.getScroll().left; },
20353
20354         /**
20355          * Sets the x/y position of an element to the location of the
20356          * target element.
20357          * @method moveToEl
20358          * @param {HTMLElement} moveEl      The element to move
20359          * @param {HTMLElement} targetEl    The position reference element
20360          * @static
20361          */
20362         moveToEl: function (moveEl, targetEl) {
20363             var aCoord = Roo.lib.Dom.getXY(targetEl);
20364             Roo.lib.Dom.setXY(moveEl, aCoord);
20365         },
20366
20367         /**
20368          * Numeric array sort function
20369          * @method numericSort
20370          * @static
20371          */
20372         numericSort: function(a, b) { return (a - b); },
20373
20374         /**
20375          * Internal counter
20376          * @property _timeoutCount
20377          * @private
20378          * @static
20379          */
20380         _timeoutCount: 0,
20381
20382         /**
20383          * Trying to make the load order less important.  Without this we get
20384          * an error if this file is loaded before the Event Utility.
20385          * @method _addListeners
20386          * @private
20387          * @static
20388          */
20389         _addListeners: function() {
20390             var DDM = Roo.dd.DDM;
20391             if ( Roo.lib.Event && document ) {
20392                 DDM._onLoad();
20393             } else {
20394                 if (DDM._timeoutCount > 2000) {
20395                 } else {
20396                     setTimeout(DDM._addListeners, 10);
20397                     if (document && document.body) {
20398                         DDM._timeoutCount += 1;
20399                     }
20400                 }
20401             }
20402         },
20403
20404         /**
20405          * Recursively searches the immediate parent and all child nodes for
20406          * the handle element in order to determine wheter or not it was
20407          * clicked.
20408          * @method handleWasClicked
20409          * @param node the html element to inspect
20410          * @static
20411          */
20412         handleWasClicked: function(node, id) {
20413             if (this.isHandle(id, node.id)) {
20414                 return true;
20415             } else {
20416                 // check to see if this is a text node child of the one we want
20417                 var p = node.parentNode;
20418
20419                 while (p) {
20420                     if (this.isHandle(id, p.id)) {
20421                         return true;
20422                     } else {
20423                         p = p.parentNode;
20424                     }
20425                 }
20426             }
20427
20428             return false;
20429         }
20430
20431     };
20432
20433 }();
20434
20435 // shorter alias, save a few bytes
20436 Roo.dd.DDM = Roo.dd.DragDropMgr;
20437 Roo.dd.DDM._addListeners();
20438
20439 }/*
20440  * Based on:
20441  * Ext JS Library 1.1.1
20442  * Copyright(c) 2006-2007, Ext JS, LLC.
20443  *
20444  * Originally Released Under LGPL - original licence link has changed is not relivant.
20445  *
20446  * Fork - LGPL
20447  * <script type="text/javascript">
20448  */
20449
20450 /**
20451  * @class Roo.dd.DD
20452  * A DragDrop implementation where the linked element follows the
20453  * mouse cursor during a drag.
20454  * @extends Roo.dd.DragDrop
20455  * @constructor
20456  * @param {String} id the id of the linked element
20457  * @param {String} sGroup the group of related DragDrop items
20458  * @param {object} config an object containing configurable attributes
20459  *                Valid properties for DD:
20460  *                    scroll
20461  */
20462 Roo.dd.DD = function(id, sGroup, config) {
20463     if (id) {
20464         this.init(id, sGroup, config);
20465     }
20466 };
20467
20468 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20469
20470     /**
20471      * When set to true, the utility automatically tries to scroll the browser
20472      * window wehn a drag and drop element is dragged near the viewport boundary.
20473      * Defaults to true.
20474      * @property scroll
20475      * @type boolean
20476      */
20477     scroll: true,
20478
20479     /**
20480      * Sets the pointer offset to the distance between the linked element's top
20481      * left corner and the location the element was clicked
20482      * @method autoOffset
20483      * @param {int} iPageX the X coordinate of the click
20484      * @param {int} iPageY the Y coordinate of the click
20485      */
20486     autoOffset: function(iPageX, iPageY) {
20487         var x = iPageX - this.startPageX;
20488         var y = iPageY - this.startPageY;
20489         this.setDelta(x, y);
20490     },
20491
20492     /**
20493      * Sets the pointer offset.  You can call this directly to force the
20494      * offset to be in a particular location (e.g., pass in 0,0 to set it
20495      * to the center of the object)
20496      * @method setDelta
20497      * @param {int} iDeltaX the distance from the left
20498      * @param {int} iDeltaY the distance from the top
20499      */
20500     setDelta: function(iDeltaX, iDeltaY) {
20501         this.deltaX = iDeltaX;
20502         this.deltaY = iDeltaY;
20503     },
20504
20505     /**
20506      * Sets the drag element to the location of the mousedown or click event,
20507      * maintaining the cursor location relative to the location on the element
20508      * that was clicked.  Override this if you want to place the element in a
20509      * location other than where the cursor is.
20510      * @method setDragElPos
20511      * @param {int} iPageX the X coordinate of the mousedown or drag event
20512      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20513      */
20514     setDragElPos: function(iPageX, iPageY) {
20515         // the first time we do this, we are going to check to make sure
20516         // the element has css positioning
20517
20518         var el = this.getDragEl();
20519         this.alignElWithMouse(el, iPageX, iPageY);
20520     },
20521
20522     /**
20523      * Sets the element to the location of the mousedown or click event,
20524      * maintaining the cursor location relative to the location on the element
20525      * that was clicked.  Override this if you want to place the element in a
20526      * location other than where the cursor is.
20527      * @method alignElWithMouse
20528      * @param {HTMLElement} el the element to move
20529      * @param {int} iPageX the X coordinate of the mousedown or drag event
20530      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20531      */
20532     alignElWithMouse: function(el, iPageX, iPageY) {
20533         var oCoord = this.getTargetCoord(iPageX, iPageY);
20534         var fly = el.dom ? el : Roo.fly(el);
20535         if (!this.deltaSetXY) {
20536             var aCoord = [oCoord.x, oCoord.y];
20537             fly.setXY(aCoord);
20538             var newLeft = fly.getLeft(true);
20539             var newTop  = fly.getTop(true);
20540             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20541         } else {
20542             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20543         }
20544
20545         this.cachePosition(oCoord.x, oCoord.y);
20546         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20547         return oCoord;
20548     },
20549
20550     /**
20551      * Saves the most recent position so that we can reset the constraints and
20552      * tick marks on-demand.  We need to know this so that we can calculate the
20553      * number of pixels the element is offset from its original position.
20554      * @method cachePosition
20555      * @param iPageX the current x position (optional, this just makes it so we
20556      * don't have to look it up again)
20557      * @param iPageY the current y position (optional, this just makes it so we
20558      * don't have to look it up again)
20559      */
20560     cachePosition: function(iPageX, iPageY) {
20561         if (iPageX) {
20562             this.lastPageX = iPageX;
20563             this.lastPageY = iPageY;
20564         } else {
20565             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20566             this.lastPageX = aCoord[0];
20567             this.lastPageY = aCoord[1];
20568         }
20569     },
20570
20571     /**
20572      * Auto-scroll the window if the dragged object has been moved beyond the
20573      * visible window boundary.
20574      * @method autoScroll
20575      * @param {int} x the drag element's x position
20576      * @param {int} y the drag element's y position
20577      * @param {int} h the height of the drag element
20578      * @param {int} w the width of the drag element
20579      * @private
20580      */
20581     autoScroll: function(x, y, h, w) {
20582
20583         if (this.scroll) {
20584             // The client height
20585             var clientH = Roo.lib.Dom.getViewWidth();
20586
20587             // The client width
20588             var clientW = Roo.lib.Dom.getViewHeight();
20589
20590             // The amt scrolled down
20591             var st = this.DDM.getScrollTop();
20592
20593             // The amt scrolled right
20594             var sl = this.DDM.getScrollLeft();
20595
20596             // Location of the bottom of the element
20597             var bot = h + y;
20598
20599             // Location of the right of the element
20600             var right = w + x;
20601
20602             // The distance from the cursor to the bottom of the visible area,
20603             // adjusted so that we don't scroll if the cursor is beyond the
20604             // element drag constraints
20605             var toBot = (clientH + st - y - this.deltaY);
20606
20607             // The distance from the cursor to the right of the visible area
20608             var toRight = (clientW + sl - x - this.deltaX);
20609
20610
20611             // How close to the edge the cursor must be before we scroll
20612             // var thresh = (document.all) ? 100 : 40;
20613             var thresh = 40;
20614
20615             // How many pixels to scroll per autoscroll op.  This helps to reduce
20616             // clunky scrolling. IE is more sensitive about this ... it needs this
20617             // value to be higher.
20618             var scrAmt = (document.all) ? 80 : 30;
20619
20620             // Scroll down if we are near the bottom of the visible page and the
20621             // obj extends below the crease
20622             if ( bot > clientH && toBot < thresh ) {
20623                 window.scrollTo(sl, st + scrAmt);
20624             }
20625
20626             // Scroll up if the window is scrolled down and the top of the object
20627             // goes above the top border
20628             if ( y < st && st > 0 && y - st < thresh ) {
20629                 window.scrollTo(sl, st - scrAmt);
20630             }
20631
20632             // Scroll right if the obj is beyond the right border and the cursor is
20633             // near the border.
20634             if ( right > clientW && toRight < thresh ) {
20635                 window.scrollTo(sl + scrAmt, st);
20636             }
20637
20638             // Scroll left if the window has been scrolled to the right and the obj
20639             // extends past the left border
20640             if ( x < sl && sl > 0 && x - sl < thresh ) {
20641                 window.scrollTo(sl - scrAmt, st);
20642             }
20643         }
20644     },
20645
20646     /**
20647      * Finds the location the element should be placed if we want to move
20648      * it to where the mouse location less the click offset would place us.
20649      * @method getTargetCoord
20650      * @param {int} iPageX the X coordinate of the click
20651      * @param {int} iPageY the Y coordinate of the click
20652      * @return an object that contains the coordinates (Object.x and Object.y)
20653      * @private
20654      */
20655     getTargetCoord: function(iPageX, iPageY) {
20656
20657
20658         var x = iPageX - this.deltaX;
20659         var y = iPageY - this.deltaY;
20660
20661         if (this.constrainX) {
20662             if (x < this.minX) { x = this.minX; }
20663             if (x > this.maxX) { x = this.maxX; }
20664         }
20665
20666         if (this.constrainY) {
20667             if (y < this.minY) { y = this.minY; }
20668             if (y > this.maxY) { y = this.maxY; }
20669         }
20670
20671         x = this.getTick(x, this.xTicks);
20672         y = this.getTick(y, this.yTicks);
20673
20674
20675         return {x:x, y:y};
20676     },
20677
20678     /*
20679      * Sets up config options specific to this class. Overrides
20680      * Roo.dd.DragDrop, but all versions of this method through the
20681      * inheritance chain are called
20682      */
20683     applyConfig: function() {
20684         Roo.dd.DD.superclass.applyConfig.call(this);
20685         this.scroll = (this.config.scroll !== false);
20686     },
20687
20688     /*
20689      * Event that fires prior to the onMouseDown event.  Overrides
20690      * Roo.dd.DragDrop.
20691      */
20692     b4MouseDown: function(e) {
20693         // this.resetConstraints();
20694         this.autoOffset(e.getPageX(),
20695                             e.getPageY());
20696     },
20697
20698     /*
20699      * Event that fires prior to the onDrag event.  Overrides
20700      * Roo.dd.DragDrop.
20701      */
20702     b4Drag: function(e) {
20703         this.setDragElPos(e.getPageX(),
20704                             e.getPageY());
20705     },
20706
20707     toString: function() {
20708         return ("DD " + this.id);
20709     }
20710
20711     //////////////////////////////////////////////////////////////////////////
20712     // Debugging ygDragDrop events that can be overridden
20713     //////////////////////////////////////////////////////////////////////////
20714     /*
20715     startDrag: function(x, y) {
20716     },
20717
20718     onDrag: function(e) {
20719     },
20720
20721     onDragEnter: function(e, id) {
20722     },
20723
20724     onDragOver: function(e, id) {
20725     },
20726
20727     onDragOut: function(e, id) {
20728     },
20729
20730     onDragDrop: function(e, id) {
20731     },
20732
20733     endDrag: function(e) {
20734     }
20735
20736     */
20737
20738 });/*
20739  * Based on:
20740  * Ext JS Library 1.1.1
20741  * Copyright(c) 2006-2007, Ext JS, LLC.
20742  *
20743  * Originally Released Under LGPL - original licence link has changed is not relivant.
20744  *
20745  * Fork - LGPL
20746  * <script type="text/javascript">
20747  */
20748
20749 /**
20750  * @class Roo.dd.DDProxy
20751  * A DragDrop implementation that inserts an empty, bordered div into
20752  * the document that follows the cursor during drag operations.  At the time of
20753  * the click, the frame div is resized to the dimensions of the linked html
20754  * element, and moved to the exact location of the linked element.
20755  *
20756  * References to the "frame" element refer to the single proxy element that
20757  * was created to be dragged in place of all DDProxy elements on the
20758  * page.
20759  *
20760  * @extends Roo.dd.DD
20761  * @constructor
20762  * @param {String} id the id of the linked html element
20763  * @param {String} sGroup the group of related DragDrop objects
20764  * @param {object} config an object containing configurable attributes
20765  *                Valid properties for DDProxy in addition to those in DragDrop:
20766  *                   resizeFrame, centerFrame, dragElId
20767  */
20768 Roo.dd.DDProxy = function(id, sGroup, config) {
20769     if (id) {
20770         this.init(id, sGroup, config);
20771         this.initFrame();
20772     }
20773 };
20774
20775 /**
20776  * The default drag frame div id
20777  * @property Roo.dd.DDProxy.dragElId
20778  * @type String
20779  * @static
20780  */
20781 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20782
20783 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20784
20785     /**
20786      * By default we resize the drag frame to be the same size as the element
20787      * we want to drag (this is to get the frame effect).  We can turn it off
20788      * if we want a different behavior.
20789      * @property resizeFrame
20790      * @type boolean
20791      */
20792     resizeFrame: true,
20793
20794     /**
20795      * By default the frame is positioned exactly where the drag element is, so
20796      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20797      * you do not have constraints on the obj is to have the drag frame centered
20798      * around the cursor.  Set centerFrame to true for this effect.
20799      * @property centerFrame
20800      * @type boolean
20801      */
20802     centerFrame: false,
20803
20804     /**
20805      * Creates the proxy element if it does not yet exist
20806      * @method createFrame
20807      */
20808     createFrame: function() {
20809         var self = this;
20810         var body = document.body;
20811
20812         if (!body || !body.firstChild) {
20813             setTimeout( function() { self.createFrame(); }, 50 );
20814             return;
20815         }
20816
20817         var div = this.getDragEl();
20818
20819         if (!div) {
20820             div    = document.createElement("div");
20821             div.id = this.dragElId;
20822             var s  = div.style;
20823
20824             s.position   = "absolute";
20825             s.visibility = "hidden";
20826             s.cursor     = "move";
20827             s.border     = "2px solid #aaa";
20828             s.zIndex     = 999;
20829
20830             // appendChild can blow up IE if invoked prior to the window load event
20831             // while rendering a table.  It is possible there are other scenarios
20832             // that would cause this to happen as well.
20833             body.insertBefore(div, body.firstChild);
20834         }
20835     },
20836
20837     /**
20838      * Initialization for the drag frame element.  Must be called in the
20839      * constructor of all subclasses
20840      * @method initFrame
20841      */
20842     initFrame: function() {
20843         this.createFrame();
20844     },
20845
20846     applyConfig: function() {
20847         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20848
20849         this.resizeFrame = (this.config.resizeFrame !== false);
20850         this.centerFrame = (this.config.centerFrame);
20851         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20852     },
20853
20854     /**
20855      * Resizes the drag frame to the dimensions of the clicked object, positions
20856      * it over the object, and finally displays it
20857      * @method showFrame
20858      * @param {int} iPageX X click position
20859      * @param {int} iPageY Y click position
20860      * @private
20861      */
20862     showFrame: function(iPageX, iPageY) {
20863         var el = this.getEl();
20864         var dragEl = this.getDragEl();
20865         var s = dragEl.style;
20866
20867         this._resizeProxy();
20868
20869         if (this.centerFrame) {
20870             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20871                            Math.round(parseInt(s.height, 10)/2) );
20872         }
20873
20874         this.setDragElPos(iPageX, iPageY);
20875
20876         Roo.fly(dragEl).show();
20877     },
20878
20879     /**
20880      * The proxy is automatically resized to the dimensions of the linked
20881      * element when a drag is initiated, unless resizeFrame is set to false
20882      * @method _resizeProxy
20883      * @private
20884      */
20885     _resizeProxy: function() {
20886         if (this.resizeFrame) {
20887             var el = this.getEl();
20888             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20889         }
20890     },
20891
20892     // overrides Roo.dd.DragDrop
20893     b4MouseDown: function(e) {
20894         var x = e.getPageX();
20895         var y = e.getPageY();
20896         this.autoOffset(x, y);
20897         this.setDragElPos(x, y);
20898     },
20899
20900     // overrides Roo.dd.DragDrop
20901     b4StartDrag: function(x, y) {
20902         // show the drag frame
20903         this.showFrame(x, y);
20904     },
20905
20906     // overrides Roo.dd.DragDrop
20907     b4EndDrag: function(e) {
20908         Roo.fly(this.getDragEl()).hide();
20909     },
20910
20911     // overrides Roo.dd.DragDrop
20912     // By default we try to move the element to the last location of the frame.
20913     // This is so that the default behavior mirrors that of Roo.dd.DD.
20914     endDrag: function(e) {
20915
20916         var lel = this.getEl();
20917         var del = this.getDragEl();
20918
20919         // Show the drag frame briefly so we can get its position
20920         del.style.visibility = "";
20921
20922         this.beforeMove();
20923         // Hide the linked element before the move to get around a Safari
20924         // rendering bug.
20925         lel.style.visibility = "hidden";
20926         Roo.dd.DDM.moveToEl(lel, del);
20927         del.style.visibility = "hidden";
20928         lel.style.visibility = "";
20929
20930         this.afterDrag();
20931     },
20932
20933     beforeMove : function(){
20934
20935     },
20936
20937     afterDrag : function(){
20938
20939     },
20940
20941     toString: function() {
20942         return ("DDProxy " + this.id);
20943     }
20944
20945 });
20946 /*
20947  * Based on:
20948  * Ext JS Library 1.1.1
20949  * Copyright(c) 2006-2007, Ext JS, LLC.
20950  *
20951  * Originally Released Under LGPL - original licence link has changed is not relivant.
20952  *
20953  * Fork - LGPL
20954  * <script type="text/javascript">
20955  */
20956
20957  /**
20958  * @class Roo.dd.DDTarget
20959  * A DragDrop implementation that does not move, but can be a drop
20960  * target.  You would get the same result by simply omitting implementation
20961  * for the event callbacks, but this way we reduce the processing cost of the
20962  * event listener and the callbacks.
20963  * @extends Roo.dd.DragDrop
20964  * @constructor
20965  * @param {String} id the id of the element that is a drop target
20966  * @param {String} sGroup the group of related DragDrop objects
20967  * @param {object} config an object containing configurable attributes
20968  *                 Valid properties for DDTarget in addition to those in
20969  *                 DragDrop:
20970  *                    none
20971  */
20972 Roo.dd.DDTarget = function(id, sGroup, config) {
20973     if (id) {
20974         this.initTarget(id, sGroup, config);
20975     }
20976     if (config.listeners || config.events) { 
20977        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20978             listeners : config.listeners || {}, 
20979             events : config.events || {} 
20980         });    
20981     }
20982 };
20983
20984 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20985 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20986     toString: function() {
20987         return ("DDTarget " + this.id);
20988     }
20989 });
20990 /*
20991  * Based on:
20992  * Ext JS Library 1.1.1
20993  * Copyright(c) 2006-2007, Ext JS, LLC.
20994  *
20995  * Originally Released Under LGPL - original licence link has changed is not relivant.
20996  *
20997  * Fork - LGPL
20998  * <script type="text/javascript">
20999  */
21000  
21001
21002 /**
21003  * @class Roo.dd.ScrollManager
21004  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21005  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21006  * @singleton
21007  */
21008 Roo.dd.ScrollManager = function(){
21009     var ddm = Roo.dd.DragDropMgr;
21010     var els = {};
21011     var dragEl = null;
21012     var proc = {};
21013     
21014     
21015     
21016     var onStop = function(e){
21017         dragEl = null;
21018         clearProc();
21019     };
21020     
21021     var triggerRefresh = function(){
21022         if(ddm.dragCurrent){
21023              ddm.refreshCache(ddm.dragCurrent.groups);
21024         }
21025     };
21026     
21027     var doScroll = function(){
21028         if(ddm.dragCurrent){
21029             var dds = Roo.dd.ScrollManager;
21030             if(!dds.animate){
21031                 if(proc.el.scroll(proc.dir, dds.increment)){
21032                     triggerRefresh();
21033                 }
21034             }else{
21035                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21036             }
21037         }
21038     };
21039     
21040     var clearProc = function(){
21041         if(proc.id){
21042             clearInterval(proc.id);
21043         }
21044         proc.id = 0;
21045         proc.el = null;
21046         proc.dir = "";
21047     };
21048     
21049     var startProc = function(el, dir){
21050          Roo.log('scroll startproc');
21051         clearProc();
21052         proc.el = el;
21053         proc.dir = dir;
21054         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21055     };
21056     
21057     var onFire = function(e, isDrop){
21058        
21059         if(isDrop || !ddm.dragCurrent){ return; }
21060         var dds = Roo.dd.ScrollManager;
21061         if(!dragEl || dragEl != ddm.dragCurrent){
21062             dragEl = ddm.dragCurrent;
21063             // refresh regions on drag start
21064             dds.refreshCache();
21065         }
21066         
21067         var xy = Roo.lib.Event.getXY(e);
21068         var pt = new Roo.lib.Point(xy[0], xy[1]);
21069         for(var id in els){
21070             var el = els[id], r = el._region;
21071             if(r && r.contains(pt) && el.isScrollable()){
21072                 if(r.bottom - pt.y <= dds.thresh){
21073                     if(proc.el != el){
21074                         startProc(el, "down");
21075                     }
21076                     return;
21077                 }else if(r.right - pt.x <= dds.thresh){
21078                     if(proc.el != el){
21079                         startProc(el, "left");
21080                     }
21081                     return;
21082                 }else if(pt.y - r.top <= dds.thresh){
21083                     if(proc.el != el){
21084                         startProc(el, "up");
21085                     }
21086                     return;
21087                 }else if(pt.x - r.left <= dds.thresh){
21088                     if(proc.el != el){
21089                         startProc(el, "right");
21090                     }
21091                     return;
21092                 }
21093             }
21094         }
21095         clearProc();
21096     };
21097     
21098     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21099     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21100     
21101     return {
21102         /**
21103          * Registers new overflow element(s) to auto scroll
21104          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21105          */
21106         register : function(el){
21107             if(el instanceof Array){
21108                 for(var i = 0, len = el.length; i < len; i++) {
21109                         this.register(el[i]);
21110                 }
21111             }else{
21112                 el = Roo.get(el);
21113                 els[el.id] = el;
21114             }
21115             Roo.dd.ScrollManager.els = els;
21116         },
21117         
21118         /**
21119          * Unregisters overflow element(s) so they are no longer scrolled
21120          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21121          */
21122         unregister : function(el){
21123             if(el instanceof Array){
21124                 for(var i = 0, len = el.length; i < len; i++) {
21125                         this.unregister(el[i]);
21126                 }
21127             }else{
21128                 el = Roo.get(el);
21129                 delete els[el.id];
21130             }
21131         },
21132         
21133         /**
21134          * The number of pixels from the edge of a container the pointer needs to be to 
21135          * trigger scrolling (defaults to 25)
21136          * @type Number
21137          */
21138         thresh : 25,
21139         
21140         /**
21141          * The number of pixels to scroll in each scroll increment (defaults to 50)
21142          * @type Number
21143          */
21144         increment : 100,
21145         
21146         /**
21147          * The frequency of scrolls in milliseconds (defaults to 500)
21148          * @type Number
21149          */
21150         frequency : 500,
21151         
21152         /**
21153          * True to animate the scroll (defaults to true)
21154          * @type Boolean
21155          */
21156         animate: true,
21157         
21158         /**
21159          * The animation duration in seconds - 
21160          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21161          * @type Number
21162          */
21163         animDuration: .4,
21164         
21165         /**
21166          * Manually trigger a cache refresh.
21167          */
21168         refreshCache : function(){
21169             for(var id in els){
21170                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21171                     els[id]._region = els[id].getRegion();
21172                 }
21173             }
21174         }
21175     };
21176 }();/*
21177  * Based on:
21178  * Ext JS Library 1.1.1
21179  * Copyright(c) 2006-2007, Ext JS, LLC.
21180  *
21181  * Originally Released Under LGPL - original licence link has changed is not relivant.
21182  *
21183  * Fork - LGPL
21184  * <script type="text/javascript">
21185  */
21186  
21187
21188 /**
21189  * @class Roo.dd.Registry
21190  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21191  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21192  * @singleton
21193  */
21194 Roo.dd.Registry = function(){
21195     var elements = {}; 
21196     var handles = {}; 
21197     var autoIdSeed = 0;
21198
21199     var getId = function(el, autogen){
21200         if(typeof el == "string"){
21201             return el;
21202         }
21203         var id = el.id;
21204         if(!id && autogen !== false){
21205             id = "roodd-" + (++autoIdSeed);
21206             el.id = id;
21207         }
21208         return id;
21209     };
21210     
21211     return {
21212     /**
21213      * Register a drag drop element
21214      * @param {String|HTMLElement} element The id or DOM node to register
21215      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21216      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21217      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21218      * populated in the data object (if applicable):
21219      * <pre>
21220 Value      Description<br />
21221 ---------  ------------------------------------------<br />
21222 handles    Array of DOM nodes that trigger dragging<br />
21223            for the element being registered<br />
21224 isHandle   True if the element passed in triggers<br />
21225            dragging itself, else false
21226 </pre>
21227      */
21228         register : function(el, data){
21229             data = data || {};
21230             if(typeof el == "string"){
21231                 el = document.getElementById(el);
21232             }
21233             data.ddel = el;
21234             elements[getId(el)] = data;
21235             if(data.isHandle !== false){
21236                 handles[data.ddel.id] = data;
21237             }
21238             if(data.handles){
21239                 var hs = data.handles;
21240                 for(var i = 0, len = hs.length; i < len; i++){
21241                         handles[getId(hs[i])] = data;
21242                 }
21243             }
21244         },
21245
21246     /**
21247      * Unregister a drag drop element
21248      * @param {String|HTMLElement}  element The id or DOM node to unregister
21249      */
21250         unregister : function(el){
21251             var id = getId(el, false);
21252             var data = elements[id];
21253             if(data){
21254                 delete elements[id];
21255                 if(data.handles){
21256                     var hs = data.handles;
21257                     for(var i = 0, len = hs.length; i < len; i++){
21258                         delete handles[getId(hs[i], false)];
21259                     }
21260                 }
21261             }
21262         },
21263
21264     /**
21265      * Returns the handle registered for a DOM Node by id
21266      * @param {String|HTMLElement} id The DOM node or id to look up
21267      * @return {Object} handle The custom handle data
21268      */
21269         getHandle : function(id){
21270             if(typeof id != "string"){ // must be element?
21271                 id = id.id;
21272             }
21273             return handles[id];
21274         },
21275
21276     /**
21277      * Returns the handle that is registered for the DOM node that is the target of the event
21278      * @param {Event} e The event
21279      * @return {Object} handle The custom handle data
21280      */
21281         getHandleFromEvent : function(e){
21282             var t = Roo.lib.Event.getTarget(e);
21283             return t ? handles[t.id] : null;
21284         },
21285
21286     /**
21287      * Returns a custom data object that is registered for a DOM node by id
21288      * @param {String|HTMLElement} id The DOM node or id to look up
21289      * @return {Object} data The custom data
21290      */
21291         getTarget : function(id){
21292             if(typeof id != "string"){ // must be element?
21293                 id = id.id;
21294             }
21295             return elements[id];
21296         },
21297
21298     /**
21299      * Returns a custom data object that is registered for the DOM node that is the target of the event
21300      * @param {Event} e The event
21301      * @return {Object} data The custom data
21302      */
21303         getTargetFromEvent : function(e){
21304             var t = Roo.lib.Event.getTarget(e);
21305             return t ? elements[t.id] || handles[t.id] : null;
21306         }
21307     };
21308 }();/*
21309  * Based on:
21310  * Ext JS Library 1.1.1
21311  * Copyright(c) 2006-2007, Ext JS, LLC.
21312  *
21313  * Originally Released Under LGPL - original licence link has changed is not relivant.
21314  *
21315  * Fork - LGPL
21316  * <script type="text/javascript">
21317  */
21318  
21319
21320 /**
21321  * @class Roo.dd.StatusProxy
21322  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21323  * default drag proxy used by all Roo.dd components.
21324  * @constructor
21325  * @param {Object} config
21326  */
21327 Roo.dd.StatusProxy = function(config){
21328     Roo.apply(this, config);
21329     this.id = this.id || Roo.id();
21330     this.el = new Roo.Layer({
21331         dh: {
21332             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21333                 {tag: "div", cls: "x-dd-drop-icon"},
21334                 {tag: "div", cls: "x-dd-drag-ghost"}
21335             ]
21336         }, 
21337         shadow: !config || config.shadow !== false
21338     });
21339     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21340     this.dropStatus = this.dropNotAllowed;
21341 };
21342
21343 Roo.dd.StatusProxy.prototype = {
21344     /**
21345      * @cfg {String} dropAllowed
21346      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21347      */
21348     dropAllowed : "x-dd-drop-ok",
21349     /**
21350      * @cfg {String} dropNotAllowed
21351      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21352      */
21353     dropNotAllowed : "x-dd-drop-nodrop",
21354
21355     /**
21356      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21357      * over the current target element.
21358      * @param {String} cssClass The css class for the new drop status indicator image
21359      */
21360     setStatus : function(cssClass){
21361         cssClass = cssClass || this.dropNotAllowed;
21362         if(this.dropStatus != cssClass){
21363             this.el.replaceClass(this.dropStatus, cssClass);
21364             this.dropStatus = cssClass;
21365         }
21366     },
21367
21368     /**
21369      * Resets the status indicator to the default dropNotAllowed value
21370      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21371      */
21372     reset : function(clearGhost){
21373         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21374         this.dropStatus = this.dropNotAllowed;
21375         if(clearGhost){
21376             this.ghost.update("");
21377         }
21378     },
21379
21380     /**
21381      * Updates the contents of the ghost element
21382      * @param {String} html The html that will replace the current innerHTML of the ghost element
21383      */
21384     update : function(html){
21385         if(typeof html == "string"){
21386             this.ghost.update(html);
21387         }else{
21388             this.ghost.update("");
21389             html.style.margin = "0";
21390             this.ghost.dom.appendChild(html);
21391         }
21392         // ensure float = none set?? cant remember why though.
21393         var el = this.ghost.dom.firstChild;
21394                 if(el){
21395                         Roo.fly(el).setStyle('float', 'none');
21396                 }
21397     },
21398     
21399     /**
21400      * Returns the underlying proxy {@link Roo.Layer}
21401      * @return {Roo.Layer} el
21402     */
21403     getEl : function(){
21404         return this.el;
21405     },
21406
21407     /**
21408      * Returns the ghost element
21409      * @return {Roo.Element} el
21410      */
21411     getGhost : function(){
21412         return this.ghost;
21413     },
21414
21415     /**
21416      * Hides the proxy
21417      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21418      */
21419     hide : function(clear){
21420         this.el.hide();
21421         if(clear){
21422             this.reset(true);
21423         }
21424     },
21425
21426     /**
21427      * Stops the repair animation if it's currently running
21428      */
21429     stop : function(){
21430         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21431             this.anim.stop();
21432         }
21433     },
21434
21435     /**
21436      * Displays this proxy
21437      */
21438     show : function(){
21439         this.el.show();
21440     },
21441
21442     /**
21443      * Force the Layer to sync its shadow and shim positions to the element
21444      */
21445     sync : function(){
21446         this.el.sync();
21447     },
21448
21449     /**
21450      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21451      * invalid drop operation by the item being dragged.
21452      * @param {Array} xy The XY position of the element ([x, y])
21453      * @param {Function} callback The function to call after the repair is complete
21454      * @param {Object} scope The scope in which to execute the callback
21455      */
21456     repair : function(xy, callback, scope){
21457         this.callback = callback;
21458         this.scope = scope;
21459         if(xy && this.animRepair !== false){
21460             this.el.addClass("x-dd-drag-repair");
21461             this.el.hideUnders(true);
21462             this.anim = this.el.shift({
21463                 duration: this.repairDuration || .5,
21464                 easing: 'easeOut',
21465                 xy: xy,
21466                 stopFx: true,
21467                 callback: this.afterRepair,
21468                 scope: this
21469             });
21470         }else{
21471             this.afterRepair();
21472         }
21473     },
21474
21475     // private
21476     afterRepair : function(){
21477         this.hide(true);
21478         if(typeof this.callback == "function"){
21479             this.callback.call(this.scope || this);
21480         }
21481         this.callback = null;
21482         this.scope = null;
21483     }
21484 };/*
21485  * Based on:
21486  * Ext JS Library 1.1.1
21487  * Copyright(c) 2006-2007, Ext JS, LLC.
21488  *
21489  * Originally Released Under LGPL - original licence link has changed is not relivant.
21490  *
21491  * Fork - LGPL
21492  * <script type="text/javascript">
21493  */
21494
21495 /**
21496  * @class Roo.dd.DragSource
21497  * @extends Roo.dd.DDProxy
21498  * A simple class that provides the basic implementation needed to make any element draggable.
21499  * @constructor
21500  * @param {String/HTMLElement/Element} el The container element
21501  * @param {Object} config
21502  */
21503 Roo.dd.DragSource = function(el, config){
21504     this.el = Roo.get(el);
21505     this.dragData = {};
21506     
21507     Roo.apply(this, config);
21508     
21509     if(!this.proxy){
21510         this.proxy = new Roo.dd.StatusProxy();
21511     }
21512
21513     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21514           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21515     
21516     this.dragging = false;
21517 };
21518
21519 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21520     /**
21521      * @cfg {String} dropAllowed
21522      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21523      */
21524     dropAllowed : "x-dd-drop-ok",
21525     /**
21526      * @cfg {String} dropNotAllowed
21527      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21528      */
21529     dropNotAllowed : "x-dd-drop-nodrop",
21530
21531     /**
21532      * Returns the data object associated with this drag source
21533      * @return {Object} data An object containing arbitrary data
21534      */
21535     getDragData : function(e){
21536         return this.dragData;
21537     },
21538
21539     // private
21540     onDragEnter : function(e, id){
21541         var target = Roo.dd.DragDropMgr.getDDById(id);
21542         this.cachedTarget = target;
21543         if(this.beforeDragEnter(target, e, id) !== false){
21544             if(target.isNotifyTarget){
21545                 var status = target.notifyEnter(this, e, this.dragData);
21546                 this.proxy.setStatus(status);
21547             }else{
21548                 this.proxy.setStatus(this.dropAllowed);
21549             }
21550             
21551             if(this.afterDragEnter){
21552                 /**
21553                  * An empty function by default, but provided so that you can perform a custom action
21554                  * when the dragged item enters the drop target by providing an implementation.
21555                  * @param {Roo.dd.DragDrop} target The drop target
21556                  * @param {Event} e The event object
21557                  * @param {String} id The id of the dragged element
21558                  * @method afterDragEnter
21559                  */
21560                 this.afterDragEnter(target, e, id);
21561             }
21562         }
21563     },
21564
21565     /**
21566      * An empty function by default, but provided so that you can perform a custom action
21567      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21568      * @param {Roo.dd.DragDrop} target The drop target
21569      * @param {Event} e The event object
21570      * @param {String} id The id of the dragged element
21571      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21572      */
21573     beforeDragEnter : function(target, e, id){
21574         return true;
21575     },
21576
21577     // private
21578     alignElWithMouse: function() {
21579         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21580         this.proxy.sync();
21581     },
21582
21583     // private
21584     onDragOver : function(e, id){
21585         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21586         if(this.beforeDragOver(target, e, id) !== false){
21587             if(target.isNotifyTarget){
21588                 var status = target.notifyOver(this, e, this.dragData);
21589                 this.proxy.setStatus(status);
21590             }
21591
21592             if(this.afterDragOver){
21593                 /**
21594                  * An empty function by default, but provided so that you can perform a custom action
21595                  * while the dragged item is over the drop target by providing an implementation.
21596                  * @param {Roo.dd.DragDrop} target The drop target
21597                  * @param {Event} e The event object
21598                  * @param {String} id The id of the dragged element
21599                  * @method afterDragOver
21600                  */
21601                 this.afterDragOver(target, e, id);
21602             }
21603         }
21604     },
21605
21606     /**
21607      * An empty function by default, but provided so that you can perform a custom action
21608      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21609      * @param {Roo.dd.DragDrop} target The drop target
21610      * @param {Event} e The event object
21611      * @param {String} id The id of the dragged element
21612      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21613      */
21614     beforeDragOver : function(target, e, id){
21615         return true;
21616     },
21617
21618     // private
21619     onDragOut : function(e, id){
21620         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21621         if(this.beforeDragOut(target, e, id) !== false){
21622             if(target.isNotifyTarget){
21623                 target.notifyOut(this, e, this.dragData);
21624             }
21625             this.proxy.reset();
21626             if(this.afterDragOut){
21627                 /**
21628                  * An empty function by default, but provided so that you can perform a custom action
21629                  * after the dragged item is dragged out of the target without dropping.
21630                  * @param {Roo.dd.DragDrop} target The drop target
21631                  * @param {Event} e The event object
21632                  * @param {String} id The id of the dragged element
21633                  * @method afterDragOut
21634                  */
21635                 this.afterDragOut(target, e, id);
21636             }
21637         }
21638         this.cachedTarget = null;
21639     },
21640
21641     /**
21642      * An empty function by default, but provided so that you can perform a custom action before the dragged
21643      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21644      * @param {Roo.dd.DragDrop} target The drop target
21645      * @param {Event} e The event object
21646      * @param {String} id The id of the dragged element
21647      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21648      */
21649     beforeDragOut : function(target, e, id){
21650         return true;
21651     },
21652     
21653     // private
21654     onDragDrop : function(e, id){
21655         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21656         if(this.beforeDragDrop(target, e, id) !== false){
21657             if(target.isNotifyTarget){
21658                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21659                     this.onValidDrop(target, e, id);
21660                 }else{
21661                     this.onInvalidDrop(target, e, id);
21662                 }
21663             }else{
21664                 this.onValidDrop(target, e, id);
21665             }
21666             
21667             if(this.afterDragDrop){
21668                 /**
21669                  * An empty function by default, but provided so that you can perform a custom action
21670                  * after a valid drag drop has occurred by providing an implementation.
21671                  * @param {Roo.dd.DragDrop} target The drop target
21672                  * @param {Event} e The event object
21673                  * @param {String} id The id of the dropped element
21674                  * @method afterDragDrop
21675                  */
21676                 this.afterDragDrop(target, e, id);
21677             }
21678         }
21679         delete this.cachedTarget;
21680     },
21681
21682     /**
21683      * An empty function by default, but provided so that you can perform a custom action before the dragged
21684      * item is dropped onto the target and optionally cancel the onDragDrop.
21685      * @param {Roo.dd.DragDrop} target The drop target
21686      * @param {Event} e The event object
21687      * @param {String} id The id of the dragged element
21688      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21689      */
21690     beforeDragDrop : function(target, e, id){
21691         return true;
21692     },
21693
21694     // private
21695     onValidDrop : function(target, e, id){
21696         this.hideProxy();
21697         if(this.afterValidDrop){
21698             /**
21699              * An empty function by default, but provided so that you can perform a custom action
21700              * after a valid drop has occurred by providing an implementation.
21701              * @param {Object} target The target DD 
21702              * @param {Event} e The event object
21703              * @param {String} id The id of the dropped element
21704              * @method afterInvalidDrop
21705              */
21706             this.afterValidDrop(target, e, id);
21707         }
21708     },
21709
21710     // private
21711     getRepairXY : function(e, data){
21712         return this.el.getXY();  
21713     },
21714
21715     // private
21716     onInvalidDrop : function(target, e, id){
21717         this.beforeInvalidDrop(target, e, id);
21718         if(this.cachedTarget){
21719             if(this.cachedTarget.isNotifyTarget){
21720                 this.cachedTarget.notifyOut(this, e, this.dragData);
21721             }
21722             this.cacheTarget = null;
21723         }
21724         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21725
21726         if(this.afterInvalidDrop){
21727             /**
21728              * An empty function by default, but provided so that you can perform a custom action
21729              * after an invalid drop has occurred by providing an implementation.
21730              * @param {Event} e The event object
21731              * @param {String} id The id of the dropped element
21732              * @method afterInvalidDrop
21733              */
21734             this.afterInvalidDrop(e, id);
21735         }
21736     },
21737
21738     // private
21739     afterRepair : function(){
21740         if(Roo.enableFx){
21741             this.el.highlight(this.hlColor || "c3daf9");
21742         }
21743         this.dragging = false;
21744     },
21745
21746     /**
21747      * An empty function by default, but provided so that you can perform a custom action after an invalid
21748      * drop has occurred.
21749      * @param {Roo.dd.DragDrop} target The drop target
21750      * @param {Event} e The event object
21751      * @param {String} id The id of the dragged element
21752      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21753      */
21754     beforeInvalidDrop : function(target, e, id){
21755         return true;
21756     },
21757
21758     // private
21759     handleMouseDown : function(e){
21760         if(this.dragging) {
21761             return;
21762         }
21763         var data = this.getDragData(e);
21764         if(data && this.onBeforeDrag(data, e) !== false){
21765             this.dragData = data;
21766             this.proxy.stop();
21767             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21768         } 
21769     },
21770
21771     /**
21772      * An empty function by default, but provided so that you can perform a custom action before the initial
21773      * drag event begins and optionally cancel it.
21774      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21775      * @param {Event} e The event object
21776      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21777      */
21778     onBeforeDrag : function(data, e){
21779         return true;
21780     },
21781
21782     /**
21783      * An empty function by default, but provided so that you can perform a custom action once the initial
21784      * drag event has begun.  The drag cannot be canceled from this function.
21785      * @param {Number} x The x position of the click on the dragged object
21786      * @param {Number} y The y position of the click on the dragged object
21787      */
21788     onStartDrag : Roo.emptyFn,
21789
21790     // private - YUI override
21791     startDrag : function(x, y){
21792         this.proxy.reset();
21793         this.dragging = true;
21794         this.proxy.update("");
21795         this.onInitDrag(x, y);
21796         this.proxy.show();
21797     },
21798
21799     // private
21800     onInitDrag : function(x, y){
21801         var clone = this.el.dom.cloneNode(true);
21802         clone.id = Roo.id(); // prevent duplicate ids
21803         this.proxy.update(clone);
21804         this.onStartDrag(x, y);
21805         return true;
21806     },
21807
21808     /**
21809      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21810      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21811      */
21812     getProxy : function(){
21813         return this.proxy;  
21814     },
21815
21816     /**
21817      * Hides the drag source's {@link Roo.dd.StatusProxy}
21818      */
21819     hideProxy : function(){
21820         this.proxy.hide();  
21821         this.proxy.reset(true);
21822         this.dragging = false;
21823     },
21824
21825     // private
21826     triggerCacheRefresh : function(){
21827         Roo.dd.DDM.refreshCache(this.groups);
21828     },
21829
21830     // private - override to prevent hiding
21831     b4EndDrag: function(e) {
21832     },
21833
21834     // private - override to prevent moving
21835     endDrag : function(e){
21836         this.onEndDrag(this.dragData, e);
21837     },
21838
21839     // private
21840     onEndDrag : function(data, e){
21841     },
21842     
21843     // private - pin to cursor
21844     autoOffset : function(x, y) {
21845         this.setDelta(-12, -20);
21846     }    
21847 });/*
21848  * Based on:
21849  * Ext JS Library 1.1.1
21850  * Copyright(c) 2006-2007, Ext JS, LLC.
21851  *
21852  * Originally Released Under LGPL - original licence link has changed is not relivant.
21853  *
21854  * Fork - LGPL
21855  * <script type="text/javascript">
21856  */
21857
21858
21859 /**
21860  * @class Roo.dd.DropTarget
21861  * @extends Roo.dd.DDTarget
21862  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21863  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21864  * @constructor
21865  * @param {String/HTMLElement/Element} el The container element
21866  * @param {Object} config
21867  */
21868 Roo.dd.DropTarget = function(el, config){
21869     this.el = Roo.get(el);
21870     
21871     var listeners = false; ;
21872     if (config && config.listeners) {
21873         listeners= config.listeners;
21874         delete config.listeners;
21875     }
21876     Roo.apply(this, config);
21877     
21878     if(this.containerScroll){
21879         Roo.dd.ScrollManager.register(this.el);
21880     }
21881     this.addEvents( {
21882          /**
21883          * @scope Roo.dd.DropTarget
21884          */
21885          
21886          /**
21887          * @event enter
21888          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21889          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21890          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21891          * 
21892          * IMPORTANT : it should set this.overClass and this.dropAllowed
21893          * 
21894          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21895          * @param {Event} e The event
21896          * @param {Object} data An object containing arbitrary data supplied by the drag source
21897          */
21898         "enter" : true,
21899         
21900          /**
21901          * @event over
21902          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21903          * This method will be called on every mouse movement while the drag source is over the drop target.
21904          * This default implementation simply returns the dropAllowed config value.
21905          * 
21906          * IMPORTANT : it should set this.dropAllowed
21907          * 
21908          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21909          * @param {Event} e The event
21910          * @param {Object} data An object containing arbitrary data supplied by the drag source
21911          
21912          */
21913         "over" : true,
21914         /**
21915          * @event out
21916          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21917          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21918          * overClass (if any) from the drop element.
21919          * 
21920          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21921          * @param {Event} e The event
21922          * @param {Object} data An object containing arbitrary data supplied by the drag source
21923          */
21924          "out" : true,
21925          
21926         /**
21927          * @event drop
21928          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21929          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21930          * implementation that does something to process the drop event and returns true so that the drag source's
21931          * repair action does not run.
21932          * 
21933          * IMPORTANT : it should set this.success
21934          * 
21935          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21936          * @param {Event} e The event
21937          * @param {Object} data An object containing arbitrary data supplied by the drag source
21938         */
21939          "drop" : true
21940     });
21941             
21942      
21943     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21944         this.el.dom, 
21945         this.ddGroup || this.group,
21946         {
21947             isTarget: true,
21948             listeners : listeners || {} 
21949            
21950         
21951         }
21952     );
21953
21954 };
21955
21956 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21957     /**
21958      * @cfg {String} overClass
21959      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21960      */
21961      /**
21962      * @cfg {String} ddGroup
21963      * The drag drop group to handle drop events for
21964      */
21965      
21966     /**
21967      * @cfg {String} dropAllowed
21968      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21969      */
21970     dropAllowed : "x-dd-drop-ok",
21971     /**
21972      * @cfg {String} dropNotAllowed
21973      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21974      */
21975     dropNotAllowed : "x-dd-drop-nodrop",
21976     /**
21977      * @cfg {boolean} success
21978      * set this after drop listener.. 
21979      */
21980     success : false,
21981     /**
21982      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21983      * if the drop point is valid for over/enter..
21984      */
21985     valid : false,
21986     // private
21987     isTarget : true,
21988
21989     // private
21990     isNotifyTarget : true,
21991     
21992     /**
21993      * @hide
21994      */
21995     notifyEnter : function(dd, e, data)
21996     {
21997         this.valid = true;
21998         this.fireEvent('enter', dd, e, data);
21999         if(this.overClass){
22000             this.el.addClass(this.overClass);
22001         }
22002         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22003             this.valid ? this.dropAllowed : this.dropNotAllowed
22004         );
22005     },
22006
22007     /**
22008      * @hide
22009      */
22010     notifyOver : function(dd, e, data)
22011     {
22012         this.valid = true;
22013         this.fireEvent('over', dd, e, data);
22014         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22015             this.valid ? this.dropAllowed : this.dropNotAllowed
22016         );
22017     },
22018
22019     /**
22020      * @hide
22021      */
22022     notifyOut : function(dd, e, data)
22023     {
22024         this.fireEvent('out', dd, e, data);
22025         if(this.overClass){
22026             this.el.removeClass(this.overClass);
22027         }
22028     },
22029
22030     /**
22031      * @hide
22032      */
22033     notifyDrop : function(dd, e, data)
22034     {
22035         this.success = false;
22036         this.fireEvent('drop', dd, e, data);
22037         return this.success;
22038     }
22039 });/*
22040  * Based on:
22041  * Ext JS Library 1.1.1
22042  * Copyright(c) 2006-2007, Ext JS, LLC.
22043  *
22044  * Originally Released Under LGPL - original licence link has changed is not relivant.
22045  *
22046  * Fork - LGPL
22047  * <script type="text/javascript">
22048  */
22049
22050
22051 /**
22052  * @class Roo.dd.DragZone
22053  * @extends Roo.dd.DragSource
22054  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22055  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22056  * @constructor
22057  * @param {String/HTMLElement/Element} el The container element
22058  * @param {Object} config
22059  */
22060 Roo.dd.DragZone = function(el, config){
22061     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22062     if(this.containerScroll){
22063         Roo.dd.ScrollManager.register(this.el);
22064     }
22065 };
22066
22067 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22068     /**
22069      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22070      * for auto scrolling during drag operations.
22071      */
22072     /**
22073      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22074      * method after a failed drop (defaults to "c3daf9" - light blue)
22075      */
22076
22077     /**
22078      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22079      * for a valid target to drag based on the mouse down. Override this method
22080      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22081      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22082      * @param {EventObject} e The mouse down event
22083      * @return {Object} The dragData
22084      */
22085     getDragData : function(e){
22086         return Roo.dd.Registry.getHandleFromEvent(e);
22087     },
22088     
22089     /**
22090      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22091      * this.dragData.ddel
22092      * @param {Number} x The x position of the click on the dragged object
22093      * @param {Number} y The y position of the click on the dragged object
22094      * @return {Boolean} true to continue the drag, false to cancel
22095      */
22096     onInitDrag : function(x, y){
22097         this.proxy.update(this.dragData.ddel.cloneNode(true));
22098         this.onStartDrag(x, y);
22099         return true;
22100     },
22101     
22102     /**
22103      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22104      */
22105     afterRepair : function(){
22106         if(Roo.enableFx){
22107             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22108         }
22109         this.dragging = false;
22110     },
22111
22112     /**
22113      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22114      * the XY of this.dragData.ddel
22115      * @param {EventObject} e The mouse up event
22116      * @return {Array} The xy location (e.g. [100, 200])
22117      */
22118     getRepairXY : function(e){
22119         return Roo.Element.fly(this.dragData.ddel).getXY();  
22120     }
22121 });/*
22122  * Based on:
22123  * Ext JS Library 1.1.1
22124  * Copyright(c) 2006-2007, Ext JS, LLC.
22125  *
22126  * Originally Released Under LGPL - original licence link has changed is not relivant.
22127  *
22128  * Fork - LGPL
22129  * <script type="text/javascript">
22130  */
22131 /**
22132  * @class Roo.dd.DropZone
22133  * @extends Roo.dd.DropTarget
22134  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22135  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22136  * @constructor
22137  * @param {String/HTMLElement/Element} el The container element
22138  * @param {Object} config
22139  */
22140 Roo.dd.DropZone = function(el, config){
22141     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22142 };
22143
22144 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22145     /**
22146      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22147      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22148      * provide your own custom lookup.
22149      * @param {Event} e The event
22150      * @return {Object} data The custom data
22151      */
22152     getTargetFromEvent : function(e){
22153         return Roo.dd.Registry.getTargetFromEvent(e);
22154     },
22155
22156     /**
22157      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22158      * that it has registered.  This method has no default implementation and should be overridden to provide
22159      * node-specific processing if necessary.
22160      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22161      * {@link #getTargetFromEvent} for this node)
22162      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22163      * @param {Event} e The event
22164      * @param {Object} data An object containing arbitrary data supplied by the drag source
22165      */
22166     onNodeEnter : function(n, dd, e, data){
22167         
22168     },
22169
22170     /**
22171      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22172      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22173      * overridden to provide the proper feedback.
22174      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22175      * {@link #getTargetFromEvent} for this node)
22176      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22177      * @param {Event} e The event
22178      * @param {Object} data An object containing arbitrary data supplied by the drag source
22179      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22180      * underlying {@link Roo.dd.StatusProxy} can be updated
22181      */
22182     onNodeOver : function(n, dd, e, data){
22183         return this.dropAllowed;
22184     },
22185
22186     /**
22187      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22188      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22189      * node-specific processing if necessary.
22190      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22191      * {@link #getTargetFromEvent} for this node)
22192      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22193      * @param {Event} e The event
22194      * @param {Object} data An object containing arbitrary data supplied by the drag source
22195      */
22196     onNodeOut : function(n, dd, e, data){
22197         
22198     },
22199
22200     /**
22201      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22202      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22203      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22204      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22205      * {@link #getTargetFromEvent} for this node)
22206      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22207      * @param {Event} e The event
22208      * @param {Object} data An object containing arbitrary data supplied by the drag source
22209      * @return {Boolean} True if the drop was valid, else false
22210      */
22211     onNodeDrop : function(n, dd, e, data){
22212         return false;
22213     },
22214
22215     /**
22216      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22217      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22218      * it should be overridden to provide the proper feedback if necessary.
22219      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22220      * @param {Event} e The event
22221      * @param {Object} data An object containing arbitrary data supplied by the drag source
22222      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22223      * underlying {@link Roo.dd.StatusProxy} can be updated
22224      */
22225     onContainerOver : function(dd, e, data){
22226         return this.dropNotAllowed;
22227     },
22228
22229     /**
22230      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22231      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22232      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22233      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22234      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22235      * @param {Event} e The event
22236      * @param {Object} data An object containing arbitrary data supplied by the drag source
22237      * @return {Boolean} True if the drop was valid, else false
22238      */
22239     onContainerDrop : function(dd, e, data){
22240         return false;
22241     },
22242
22243     /**
22244      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22245      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22246      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22247      * you should override this method and provide a custom implementation.
22248      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22249      * @param {Event} e The event
22250      * @param {Object} data An object containing arbitrary data supplied by the drag source
22251      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22252      * underlying {@link Roo.dd.StatusProxy} can be updated
22253      */
22254     notifyEnter : function(dd, e, data){
22255         return this.dropNotAllowed;
22256     },
22257
22258     /**
22259      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22260      * This method will be called on every mouse movement while the drag source is over the drop zone.
22261      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22262      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22263      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22264      * registered node, it will call {@link #onContainerOver}.
22265      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22266      * @param {Event} e The event
22267      * @param {Object} data An object containing arbitrary data supplied by the drag source
22268      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22269      * underlying {@link Roo.dd.StatusProxy} can be updated
22270      */
22271     notifyOver : function(dd, e, data){
22272         var n = this.getTargetFromEvent(e);
22273         if(!n){ // not over valid drop target
22274             if(this.lastOverNode){
22275                 this.onNodeOut(this.lastOverNode, dd, e, data);
22276                 this.lastOverNode = null;
22277             }
22278             return this.onContainerOver(dd, e, data);
22279         }
22280         if(this.lastOverNode != n){
22281             if(this.lastOverNode){
22282                 this.onNodeOut(this.lastOverNode, dd, e, data);
22283             }
22284             this.onNodeEnter(n, dd, e, data);
22285             this.lastOverNode = n;
22286         }
22287         return this.onNodeOver(n, dd, e, data);
22288     },
22289
22290     /**
22291      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22292      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22293      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22294      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22295      * @param {Event} e The event
22296      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22297      */
22298     notifyOut : function(dd, e, data){
22299         if(this.lastOverNode){
22300             this.onNodeOut(this.lastOverNode, dd, e, data);
22301             this.lastOverNode = null;
22302         }
22303     },
22304
22305     /**
22306      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22307      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22308      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22309      * otherwise it will call {@link #onContainerDrop}.
22310      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22311      * @param {Event} e The event
22312      * @param {Object} data An object containing arbitrary data supplied by the drag source
22313      * @return {Boolean} True if the drop was valid, else false
22314      */
22315     notifyDrop : function(dd, e, data){
22316         if(this.lastOverNode){
22317             this.onNodeOut(this.lastOverNode, dd, e, data);
22318             this.lastOverNode = null;
22319         }
22320         var n = this.getTargetFromEvent(e);
22321         return n ?
22322             this.onNodeDrop(n, dd, e, data) :
22323             this.onContainerDrop(dd, e, data);
22324     },
22325
22326     // private
22327     triggerCacheRefresh : function(){
22328         Roo.dd.DDM.refreshCache(this.groups);
22329     }  
22330 });