Popover overhall - with example
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         }
672         
673     });
674
675
676 })();
677
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
680                 "Roo.app", "Roo.ux",
681                 "Roo.bootstrap",
682                 "Roo.bootstrap.dash");
683 /*
684  * Based on:
685  * Ext JS Library 1.1.1
686  * Copyright(c) 2006-2007, Ext JS, LLC.
687  *
688  * Originally Released Under LGPL - original licence link has changed is not relivant.
689  *
690  * Fork - LGPL
691  * <script type="text/javascript">
692  */
693
694 (function() {    
695     // wrappedn so fnCleanup is not in global scope...
696     if(Roo.isIE) {
697         function fnCleanUp() {
698             var p = Function.prototype;
699             delete p.createSequence;
700             delete p.defer;
701             delete p.createDelegate;
702             delete p.createCallback;
703             delete p.createInterceptor;
704
705             window.detachEvent("onunload", fnCleanUp);
706         }
707         window.attachEvent("onunload", fnCleanUp);
708     }
709 })();
710
711
712 /**
713  * @class Function
714  * These functions are available on every Function object (any JavaScript function).
715  */
716 Roo.apply(Function.prototype, {
717      /**
718      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720      * Will create a function that is bound to those 2 args.
721      * @return {Function} The new function
722     */
723     createCallback : function(/*args...*/){
724         // make args available, in function below
725         var args = arguments;
726         var method = this;
727         return function() {
728             return method.apply(window, args);
729         };
730     },
731
732     /**
733      * Creates a delegate (callback) that sets the scope to obj.
734      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735      * Will create a function that is automatically scoped to this.
736      * @param {Object} obj (optional) The object for which the scope is set
737      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739      *                                             if a number the args are inserted at the specified position
740      * @return {Function} The new function
741      */
742     createDelegate : function(obj, args, appendArgs){
743         var method = this;
744         return function() {
745             var callArgs = args || arguments;
746             if(appendArgs === true){
747                 callArgs = Array.prototype.slice.call(arguments, 0);
748                 callArgs = callArgs.concat(args);
749             }else if(typeof appendArgs == "number"){
750                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
753             }
754             return method.apply(obj || window, callArgs);
755         };
756     },
757
758     /**
759      * Calls this function after the number of millseconds specified.
760      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761      * @param {Object} obj (optional) The object for which the scope is set
762      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764      *                                             if a number the args are inserted at the specified position
765      * @return {Number} The timeout id that can be used with clearTimeout
766      */
767     defer : function(millis, obj, args, appendArgs){
768         var fn = this.createDelegate(obj, args, appendArgs);
769         if(millis){
770             return setTimeout(fn, millis);
771         }
772         fn();
773         return 0;
774     },
775     /**
776      * Create a combined function call sequence of the original function + the passed function.
777      * The resulting function returns the results of the original function.
778      * The passed fcn is called with the parameters of the original function
779      * @param {Function} fcn The function to sequence
780      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781      * @return {Function} The new function
782      */
783     createSequence : function(fcn, scope){
784         if(typeof fcn != "function"){
785             return this;
786         }
787         var method = this;
788         return function() {
789             var retval = method.apply(this || window, arguments);
790             fcn.apply(scope || this || window, arguments);
791             return retval;
792         };
793     },
794
795     /**
796      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797      * The resulting function returns the results of the original function.
798      * The passed fcn is called with the parameters of the original function.
799      * @addon
800      * @param {Function} fcn The function to call before the original
801      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802      * @return {Function} The new function
803      */
804     createInterceptor : function(fcn, scope){
805         if(typeof fcn != "function"){
806             return this;
807         }
808         var method = this;
809         return function() {
810             fcn.target = this;
811             fcn.method = method;
812             if(fcn.apply(scope || this || window, arguments) === false){
813                 return;
814             }
815             return method.apply(this || window, arguments);
816         };
817     }
818 });
819 /*
820  * Based on:
821  * Ext JS Library 1.1.1
822  * Copyright(c) 2006-2007, Ext JS, LLC.
823  *
824  * Originally Released Under LGPL - original licence link has changed is not relivant.
825  *
826  * Fork - LGPL
827  * <script type="text/javascript">
828  */
829
830 Roo.applyIf(String, {
831     
832     /** @scope String */
833     
834     /**
835      * Escapes the passed string for ' and \
836      * @param {String} string The string to escape
837      * @return {String} The escaped string
838      * @static
839      */
840     escape : function(string) {
841         return string.replace(/('|\\)/g, "\\$1");
842     },
843
844     /**
845      * Pads the left side of a string with a specified character.  This is especially useful
846      * for normalizing number and date strings.  Example usage:
847      * <pre><code>
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
850 </code></pre>
851      * @param {String} string The original string
852      * @param {Number} size The total length of the output string
853      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854      * @return {String} The padded string
855      * @static
856      */
857     leftPad : function (val, size, ch) {
858         var result = new String(val);
859         if(ch === null || ch === undefined || ch === '') {
860             ch = " ";
861         }
862         while (result.length < size) {
863             result = ch + result;
864         }
865         return result;
866     },
867
868     /**
869      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
870      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
871      * <pre><code>
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
875 </code></pre>
876      * @param {String} string The tokenized string to be formatted
877      * @param {String} value1 The value to replace token {0}
878      * @param {String} value2 Etc...
879      * @return {String} The formatted string
880      * @static
881      */
882     format : function(format){
883         var args = Array.prototype.slice.call(arguments, 1);
884         return format.replace(/\{(\d+)\}/g, function(m, i){
885             return Roo.util.Format.htmlEncode(args[i]);
886         });
887     }
888   
889     
890 });
891
892 /**
893  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
894  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
895  * they are already different, the first value passed in is returned.  Note that this method returns the new value
896  * but does not change the current string.
897  * <pre><code>
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
900
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
903 </code></pre>
904  * @param {String} value The value to compare to the current string
905  * @param {String} other The new value to use if the string already equals the first value passed in
906  * @return {String} The new value
907  */
908  
909 String.prototype.toggle = function(value, other){
910     return this == value ? other : value;
911 };
912
913
914 /**
915   * Remove invalid unicode characters from a string 
916   *
917   * @return {String} The clean string
918   */
919 String.prototype.unicodeClean = function () {
920     return this.replace(/[\s\S]/g,
921         function(character) {
922             if (character.charCodeAt()< 256) {
923               return character;
924            }
925            try {
926                 encodeURIComponent(character);
927            } catch(e) { 
928               return '';
929            }
930            return character;
931         }
932     );
933 };
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  /**
947  * @class Number
948  */
949 Roo.applyIf(Number.prototype, {
950     /**
951      * Checks whether or not the current number is within a desired range.  If the number is already within the
952      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953      * exceeded.  Note that this method returns the constrained value but does not change the current number.
954      * @param {Number} min The minimum number in the range
955      * @param {Number} max The maximum number in the range
956      * @return {Number} The constrained value if outside the range, otherwise the current value
957      */
958     constrain : function(min, max){
959         return Math.min(Math.max(this, min), max);
960     }
961 });/*
962  * Based on:
963  * Ext JS Library 1.1.1
964  * Copyright(c) 2006-2007, Ext JS, LLC.
965  *
966  * Originally Released Under LGPL - original licence link has changed is not relivant.
967  *
968  * Fork - LGPL
969  * <script type="text/javascript">
970  */
971  /**
972  * @class Array
973  */
974 Roo.applyIf(Array.prototype, {
975     /**
976      * 
977      * Checks whether or not the specified object exists in the array.
978      * @param {Object} o The object to check for
979      * @return {Number} The index of o in the array (or -1 if it is not found)
980      */
981     indexOf : function(o){
982        for (var i = 0, len = this.length; i < len; i++){
983               if(this[i] == o) { return i; }
984        }
985            return -1;
986     },
987
988     /**
989      * Removes the specified object from the array.  If the object is not found nothing happens.
990      * @param {Object} o The object to remove
991      */
992     remove : function(o){
993        var index = this.indexOf(o);
994        if(index != -1){
995            this.splice(index, 1);
996        }
997     },
998     /**
999      * Map (JS 1.6 compatibility)
1000      * @param {Function} function  to call
1001      */
1002     map : function(fun )
1003     {
1004         var len = this.length >>> 0;
1005         if (typeof fun != "function") {
1006             throw new TypeError();
1007         }
1008         var res = new Array(len);
1009         var thisp = arguments[1];
1010         for (var i = 0; i < len; i++)
1011         {
1012             if (i in this) {
1013                 res[i] = fun.call(thisp, this[i], i, this);
1014             }
1015         }
1016
1017         return res;
1018     },
1019     /**
1020      * equals
1021      * @param {Array} o The array to compare to
1022      * @returns {Boolean} true if the same
1023      */
1024     equals : function(b)
1025     {
1026         // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1027         if (this === b) {
1028             return true;
1029          }
1030         if (b == null) {
1031             return false;
1032         }
1033         if (this.length !== b.length) {
1034             return false;
1035         }
1036       
1037         // sort?? a.sort().equals(b.sort());
1038       
1039         for (var i = 0; i < this.length; ++i) {
1040             if (this[i] !== b[i]) {
1041                 return false;
1042             }
1043         }
1044         return true;
1045     }
1046 });
1047
1048
1049  
1050 /*
1051  * Based on:
1052  * Ext JS Library 1.1.1
1053  * Copyright(c) 2006-2007, Ext JS, LLC.
1054  *
1055  * Originally Released Under LGPL - original licence link has changed is not relivant.
1056  *
1057  * Fork - LGPL
1058  * <script type="text/javascript">
1059  */
1060
1061 /**
1062  * @class Date
1063  *
1064  * The date parsing and format syntax is a subset of
1065  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1066  * supported will provide results equivalent to their PHP versions.
1067  *
1068  * Following is the list of all currently supported formats:
1069  *<pre>
1070 Sample date:
1071 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1072
1073 Format  Output      Description
1074 ------  ----------  --------------------------------------------------------------
1075   d      10         Day of the month, 2 digits with leading zeros
1076   D      Wed        A textual representation of a day, three letters
1077   j      10         Day of the month without leading zeros
1078   l      Wednesday  A full textual representation of the day of the week
1079   S      th         English ordinal day of month suffix, 2 chars (use with j)
1080   w      3          Numeric representation of the day of the week
1081   z      9          The julian date, or day of the year (0-365)
1082   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1083   F      January    A full textual representation of the month
1084   m      01         Numeric representation of a month, with leading zeros
1085   M      Jan        Month name abbreviation, three letters
1086   n      1          Numeric representation of a month, without leading zeros
1087   t      31         Number of days in the given month
1088   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1089   Y      2007       A full numeric representation of a year, 4 digits
1090   y      07         A two digit representation of a year
1091   a      pm         Lowercase Ante meridiem and Post meridiem
1092   A      PM         Uppercase Ante meridiem and Post meridiem
1093   g      3          12-hour format of an hour without leading zeros
1094   G      15         24-hour format of an hour without leading zeros
1095   h      03         12-hour format of an hour with leading zeros
1096   H      15         24-hour format of an hour with leading zeros
1097   i      05         Minutes with leading zeros
1098   s      01         Seconds, with leading zeros
1099   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1100   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1101   T      CST        Timezone setting of the machine running the code
1102   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1103 </pre>
1104  *
1105  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1106  * <pre><code>
1107 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1108 document.write(dt.format('Y-m-d'));                         //2007-01-10
1109 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1110 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
1111  </code></pre>
1112  *
1113  * Here are some standard date/time patterns that you might find helpful.  They
1114  * are not part of the source of Date.js, but to use them you can simply copy this
1115  * block of code into any script that is included after Date.js and they will also become
1116  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1117  * <pre><code>
1118 Date.patterns = {
1119     ISO8601Long:"Y-m-d H:i:s",
1120     ISO8601Short:"Y-m-d",
1121     ShortDate: "n/j/Y",
1122     LongDate: "l, F d, Y",
1123     FullDateTime: "l, F d, Y g:i:s A",
1124     MonthDay: "F d",
1125     ShortTime: "g:i A",
1126     LongTime: "g:i:s A",
1127     SortableDateTime: "Y-m-d\\TH:i:s",
1128     UniversalSortableDateTime: "Y-m-d H:i:sO",
1129     YearMonth: "F, Y"
1130 };
1131 </code></pre>
1132  *
1133  * Example usage:
1134  * <pre><code>
1135 var dt = new Date();
1136 document.write(dt.format(Date.patterns.ShortDate));
1137  </code></pre>
1138  */
1139
1140 /*
1141  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1142  * They generate precompiled functions from date formats instead of parsing and
1143  * processing the pattern every time you format a date.  These functions are available
1144  * on every Date object (any javascript function).
1145  *
1146  * The original article and download are here:
1147  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1148  *
1149  */
1150  
1151  
1152  // was in core
1153 /**
1154  Returns the number of milliseconds between this date and date
1155  @param {Date} date (optional) Defaults to now
1156  @return {Number} The diff in milliseconds
1157  @member Date getElapsed
1158  */
1159 Date.prototype.getElapsed = function(date) {
1160         return Math.abs((date || new Date()).getTime()-this.getTime());
1161 };
1162 // was in date file..
1163
1164
1165 // private
1166 Date.parseFunctions = {count:0};
1167 // private
1168 Date.parseRegexes = [];
1169 // private
1170 Date.formatFunctions = {count:0};
1171
1172 // private
1173 Date.prototype.dateFormat = function(format) {
1174     if (Date.formatFunctions[format] == null) {
1175         Date.createNewFormat(format);
1176     }
1177     var func = Date.formatFunctions[format];
1178     return this[func]();
1179 };
1180
1181
1182 /**
1183  * Formats a date given the supplied format string
1184  * @param {String} format The format string
1185  * @return {String} The formatted date
1186  * @method
1187  */
1188 Date.prototype.format = Date.prototype.dateFormat;
1189
1190 // private
1191 Date.createNewFormat = function(format) {
1192     var funcName = "format" + Date.formatFunctions.count++;
1193     Date.formatFunctions[format] = funcName;
1194     var code = "Date.prototype." + funcName + " = function(){return ";
1195     var special = false;
1196     var ch = '';
1197     for (var i = 0; i < format.length; ++i) {
1198         ch = format.charAt(i);
1199         if (!special && ch == "\\") {
1200             special = true;
1201         }
1202         else if (special) {
1203             special = false;
1204             code += "'" + String.escape(ch) + "' + ";
1205         }
1206         else {
1207             code += Date.getFormatCode(ch);
1208         }
1209     }
1210     /** eval:var:zzzzzzzzzzzzz */
1211     eval(code.substring(0, code.length - 3) + ";}");
1212 };
1213
1214 // private
1215 Date.getFormatCode = function(character) {
1216     switch (character) {
1217     case "d":
1218         return "String.leftPad(this.getDate(), 2, '0') + ";
1219     case "D":
1220         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1221     case "j":
1222         return "this.getDate() + ";
1223     case "l":
1224         return "Date.dayNames[this.getDay()] + ";
1225     case "S":
1226         return "this.getSuffix() + ";
1227     case "w":
1228         return "this.getDay() + ";
1229     case "z":
1230         return "this.getDayOfYear() + ";
1231     case "W":
1232         return "this.getWeekOfYear() + ";
1233     case "F":
1234         return "Date.monthNames[this.getMonth()] + ";
1235     case "m":
1236         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1237     case "M":
1238         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1239     case "n":
1240         return "(this.getMonth() + 1) + ";
1241     case "t":
1242         return "this.getDaysInMonth() + ";
1243     case "L":
1244         return "(this.isLeapYear() ? 1 : 0) + ";
1245     case "Y":
1246         return "this.getFullYear() + ";
1247     case "y":
1248         return "('' + this.getFullYear()).substring(2, 4) + ";
1249     case "a":
1250         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1251     case "A":
1252         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1253     case "g":
1254         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1255     case "G":
1256         return "this.getHours() + ";
1257     case "h":
1258         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1259     case "H":
1260         return "String.leftPad(this.getHours(), 2, '0') + ";
1261     case "i":
1262         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1263     case "s":
1264         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1265     case "O":
1266         return "this.getGMTOffset() + ";
1267     case "P":
1268         return "this.getGMTColonOffset() + ";
1269     case "T":
1270         return "this.getTimezone() + ";
1271     case "Z":
1272         return "(this.getTimezoneOffset() * -60) + ";
1273     default:
1274         return "'" + String.escape(character) + "' + ";
1275     }
1276 };
1277
1278 /**
1279  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1280  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1281  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1282  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1283  * string or the parse operation will fail.
1284  * Example Usage:
1285 <pre><code>
1286 //dt = Fri May 25 2007 (current date)
1287 var dt = new Date();
1288
1289 //dt = Thu May 25 2006 (today's month/day in 2006)
1290 dt = Date.parseDate("2006", "Y");
1291
1292 //dt = Sun Jan 15 2006 (all date parts specified)
1293 dt = Date.parseDate("2006-1-15", "Y-m-d");
1294
1295 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1296 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1297 </code></pre>
1298  * @param {String} input The unparsed date as a string
1299  * @param {String} format The format the date is in
1300  * @return {Date} The parsed date
1301  * @static
1302  */
1303 Date.parseDate = function(input, format) {
1304     if (Date.parseFunctions[format] == null) {
1305         Date.createParser(format);
1306     }
1307     var func = Date.parseFunctions[format];
1308     return Date[func](input);
1309 };
1310 /**
1311  * @private
1312  */
1313
1314 Date.createParser = function(format) {
1315     var funcName = "parse" + Date.parseFunctions.count++;
1316     var regexNum = Date.parseRegexes.length;
1317     var currentGroup = 1;
1318     Date.parseFunctions[format] = funcName;
1319
1320     var code = "Date." + funcName + " = function(input){\n"
1321         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1322         + "var d = new Date();\n"
1323         + "y = d.getFullYear();\n"
1324         + "m = d.getMonth();\n"
1325         + "d = d.getDate();\n"
1326         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1327         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1328         + "if (results && results.length > 0) {";
1329     var regex = "";
1330
1331     var special = false;
1332     var ch = '';
1333     for (var i = 0; i < format.length; ++i) {
1334         ch = format.charAt(i);
1335         if (!special && ch == "\\") {
1336             special = true;
1337         }
1338         else if (special) {
1339             special = false;
1340             regex += String.escape(ch);
1341         }
1342         else {
1343             var obj = Date.formatCodeToRegex(ch, currentGroup);
1344             currentGroup += obj.g;
1345             regex += obj.s;
1346             if (obj.g && obj.c) {
1347                 code += obj.c;
1348             }
1349         }
1350     }
1351
1352     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1353         + "{v = new Date(y, m, d, h, i, s);}\n"
1354         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1355         + "{v = new Date(y, m, d, h, i);}\n"
1356         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1357         + "{v = new Date(y, m, d, h);}\n"
1358         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1359         + "{v = new Date(y, m, d);}\n"
1360         + "else if (y >= 0 && m >= 0)\n"
1361         + "{v = new Date(y, m);}\n"
1362         + "else if (y >= 0)\n"
1363         + "{v = new Date(y);}\n"
1364         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1365         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1366         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1367         + ";}";
1368
1369     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1370     /** eval:var:zzzzzzzzzzzzz */
1371     eval(code);
1372 };
1373
1374 // private
1375 Date.formatCodeToRegex = function(character, currentGroup) {
1376     switch (character) {
1377     case "D":
1378         return {g:0,
1379         c:null,
1380         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1381     case "j":
1382         return {g:1,
1383             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{1,2})"}; // day of month without leading zeroes
1385     case "d":
1386         return {g:1,
1387             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1388             s:"(\\d{2})"}; // day of month with leading zeroes
1389     case "l":
1390         return {g:0,
1391             c:null,
1392             s:"(?:" + Date.dayNames.join("|") + ")"};
1393     case "S":
1394         return {g:0,
1395             c:null,
1396             s:"(?:st|nd|rd|th)"};
1397     case "w":
1398         return {g:0,
1399             c:null,
1400             s:"\\d"};
1401     case "z":
1402         return {g:0,
1403             c:null,
1404             s:"(?:\\d{1,3})"};
1405     case "W":
1406         return {g:0,
1407             c:null,
1408             s:"(?:\\d{2})"};
1409     case "F":
1410         return {g:1,
1411             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1412             s:"(" + Date.monthNames.join("|") + ")"};
1413     case "M":
1414         return {g:1,
1415             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1416             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1417     case "n":
1418         return {g:1,
1419             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1420             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1421     case "m":
1422         return {g:1,
1423             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1424             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1425     case "t":
1426         return {g:0,
1427             c:null,
1428             s:"\\d{1,2}"};
1429     case "L":
1430         return {g:0,
1431             c:null,
1432             s:"(?:1|0)"};
1433     case "Y":
1434         return {g:1,
1435             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{4})"};
1437     case "y":
1438         return {g:1,
1439             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1440                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1441             s:"(\\d{1,2})"};
1442     case "a":
1443         return {g:1,
1444             c:"if (results[" + currentGroup + "] == 'am') {\n"
1445                 + "if (h == 12) { h = 0; }\n"
1446                 + "} else { if (h < 12) { h += 12; }}",
1447             s:"(am|pm)"};
1448     case "A":
1449         return {g:1,
1450             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1451                 + "if (h == 12) { h = 0; }\n"
1452                 + "} else { if (h < 12) { h += 12; }}",
1453             s:"(AM|PM)"};
1454     case "g":
1455     case "G":
1456         return {g:1,
1457             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1458             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1459     case "h":
1460     case "H":
1461         return {g:1,
1462             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1463             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1464     case "i":
1465         return {g:1,
1466             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1467             s:"(\\d{2})"};
1468     case "s":
1469         return {g:1,
1470             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1471             s:"(\\d{2})"};
1472     case "O":
1473         return {g:1,
1474             c:[
1475                 "o = results[", currentGroup, "];\n",
1476                 "var sn = o.substring(0,1);\n", // get + / - sign
1477                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1478                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1479                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1480                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1481             ].join(""),
1482             s:"([+\-]\\d{2,4})"};
1483     
1484     
1485     case "P":
1486         return {g:1,
1487                 c:[
1488                    "o = results[", currentGroup, "];\n",
1489                    "var sn = o.substring(0,1);\n",
1490                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1491                    "var mn = o.substring(4,6) % 60;\n",
1492                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1493                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1494             ].join(""),
1495             s:"([+\-]\\d{4})"};
1496     case "T":
1497         return {g:0,
1498             c:null,
1499             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1500     case "Z":
1501         return {g:1,
1502             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1503                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1504             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1505     default:
1506         return {g:0,
1507             c:null,
1508             s:String.escape(character)};
1509     }
1510 };
1511
1512 /**
1513  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1514  * @return {String} The abbreviated timezone name (e.g. 'CST')
1515  */
1516 Date.prototype.getTimezone = function() {
1517     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1518 };
1519
1520 /**
1521  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1522  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1523  */
1524 Date.prototype.getGMTOffset = function() {
1525     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1526         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1527         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1528 };
1529
1530 /**
1531  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1532  * @return {String} 2-characters representing hours and 2-characters representing minutes
1533  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1534  */
1535 Date.prototype.getGMTColonOffset = function() {
1536         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1538                 + ":"
1539                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1540 }
1541
1542 /**
1543  * Get the numeric day number of the year, adjusted for leap year.
1544  * @return {Number} 0 through 364 (365 in leap years)
1545  */
1546 Date.prototype.getDayOfYear = function() {
1547     var num = 0;
1548     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1549     for (var i = 0; i < this.getMonth(); ++i) {
1550         num += Date.daysInMonth[i];
1551     }
1552     return num + this.getDate() - 1;
1553 };
1554
1555 /**
1556  * Get the string representation of the numeric week number of the year
1557  * (equivalent to the format specifier 'W').
1558  * @return {String} '00' through '52'
1559  */
1560 Date.prototype.getWeekOfYear = function() {
1561     // Skip to Thursday of this week
1562     var now = this.getDayOfYear() + (4 - this.getDay());
1563     // Find the first Thursday of the year
1564     var jan1 = new Date(this.getFullYear(), 0, 1);
1565     var then = (7 - jan1.getDay() + 4);
1566     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1567 };
1568
1569 /**
1570  * Whether or not the current date is in a leap year.
1571  * @return {Boolean} True if the current date is in a leap year, else false
1572  */
1573 Date.prototype.isLeapYear = function() {
1574     var year = this.getFullYear();
1575     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1576 };
1577
1578 /**
1579  * Get the first day of the current month, adjusted for leap year.  The returned value
1580  * is the numeric day index within the week (0-6) which can be used in conjunction with
1581  * the {@link #monthNames} array to retrieve the textual day name.
1582  * Example:
1583  *<pre><code>
1584 var dt = new Date('1/10/2007');
1585 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1586 </code></pre>
1587  * @return {Number} The day number (0-6)
1588  */
1589 Date.prototype.getFirstDayOfMonth = function() {
1590     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1591     return (day < 0) ? (day + 7) : day;
1592 };
1593
1594 /**
1595  * Get the last day of the current month, adjusted for leap year.  The returned value
1596  * is the numeric day index within the week (0-6) which can be used in conjunction with
1597  * the {@link #monthNames} array to retrieve the textual day name.
1598  * Example:
1599  *<pre><code>
1600 var dt = new Date('1/10/2007');
1601 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1602 </code></pre>
1603  * @return {Number} The day number (0-6)
1604  */
1605 Date.prototype.getLastDayOfMonth = function() {
1606     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1607     return (day < 0) ? (day + 7) : day;
1608 };
1609
1610
1611 /**
1612  * Get the first date of this date's month
1613  * @return {Date}
1614  */
1615 Date.prototype.getFirstDateOfMonth = function() {
1616     return new Date(this.getFullYear(), this.getMonth(), 1);
1617 };
1618
1619 /**
1620  * Get the last date of this date's month
1621  * @return {Date}
1622  */
1623 Date.prototype.getLastDateOfMonth = function() {
1624     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1625 };
1626 /**
1627  * Get the number of days in the current month, adjusted for leap year.
1628  * @return {Number} The number of days in the month
1629  */
1630 Date.prototype.getDaysInMonth = function() {
1631     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1632     return Date.daysInMonth[this.getMonth()];
1633 };
1634
1635 /**
1636  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1637  * @return {String} 'st, 'nd', 'rd' or 'th'
1638  */
1639 Date.prototype.getSuffix = function() {
1640     switch (this.getDate()) {
1641         case 1:
1642         case 21:
1643         case 31:
1644             return "st";
1645         case 2:
1646         case 22:
1647             return "nd";
1648         case 3:
1649         case 23:
1650             return "rd";
1651         default:
1652             return "th";
1653     }
1654 };
1655
1656 // private
1657 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1658
1659 /**
1660  * An array of textual month names.
1661  * Override these values for international dates, for example...
1662  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1663  * @type Array
1664  * @static
1665  */
1666 Date.monthNames =
1667    ["January",
1668     "February",
1669     "March",
1670     "April",
1671     "May",
1672     "June",
1673     "July",
1674     "August",
1675     "September",
1676     "October",
1677     "November",
1678     "December"];
1679
1680 /**
1681  * An array of textual day names.
1682  * Override these values for international dates, for example...
1683  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1684  * @type Array
1685  * @static
1686  */
1687 Date.dayNames =
1688    ["Sunday",
1689     "Monday",
1690     "Tuesday",
1691     "Wednesday",
1692     "Thursday",
1693     "Friday",
1694     "Saturday"];
1695
1696 // private
1697 Date.y2kYear = 50;
1698 // private
1699 Date.monthNumbers = {
1700     Jan:0,
1701     Feb:1,
1702     Mar:2,
1703     Apr:3,
1704     May:4,
1705     Jun:5,
1706     Jul:6,
1707     Aug:7,
1708     Sep:8,
1709     Oct:9,
1710     Nov:10,
1711     Dec:11};
1712
1713 /**
1714  * Creates and returns a new Date instance with the exact same date value as the called instance.
1715  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1716  * variable will also be changed.  When the intention is to create a new variable that will not
1717  * modify the original instance, you should create a clone.
1718  *
1719  * Example of correctly cloning a date:
1720  * <pre><code>
1721 //wrong way:
1722 var orig = new Date('10/1/2006');
1723 var copy = orig;
1724 copy.setDate(5);
1725 document.write(orig);  //returns 'Thu Oct 05 2006'!
1726
1727 //correct way:
1728 var orig = new Date('10/1/2006');
1729 var copy = orig.clone();
1730 copy.setDate(5);
1731 document.write(orig);  //returns 'Thu Oct 01 2006'
1732 </code></pre>
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.clone = function() {
1736         return new Date(this.getTime());
1737 };
1738
1739 /**
1740  * Clears any time information from this date
1741  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1742  @return {Date} this or the clone
1743  */
1744 Date.prototype.clearTime = function(clone){
1745     if(clone){
1746         return this.clone().clearTime();
1747     }
1748     this.setHours(0);
1749     this.setMinutes(0);
1750     this.setSeconds(0);
1751     this.setMilliseconds(0);
1752     return this;
1753 };
1754
1755 // private
1756 // safari setMonth is broken -- check that this is only donw once...
1757 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1758     Date.brokenSetMonth = Date.prototype.setMonth;
1759         Date.prototype.setMonth = function(num){
1760                 if(num <= -1){
1761                         var n = Math.ceil(-num);
1762                         var back_year = Math.ceil(n/12);
1763                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1764                         this.setFullYear(this.getFullYear() - back_year);
1765                         return Date.brokenSetMonth.call(this, month);
1766                 } else {
1767                         return Date.brokenSetMonth.apply(this, arguments);
1768                 }
1769         };
1770 }
1771
1772 /** Date interval constant 
1773 * @static 
1774 * @type String */
1775 Date.MILLI = "ms";
1776 /** Date interval constant 
1777 * @static 
1778 * @type String */
1779 Date.SECOND = "s";
1780 /** Date interval constant 
1781 * @static 
1782 * @type String */
1783 Date.MINUTE = "mi";
1784 /** Date interval constant 
1785 * @static 
1786 * @type String */
1787 Date.HOUR = "h";
1788 /** Date interval constant 
1789 * @static 
1790 * @type String */
1791 Date.DAY = "d";
1792 /** Date interval constant 
1793 * @static 
1794 * @type String */
1795 Date.MONTH = "mo";
1796 /** Date interval constant 
1797 * @static 
1798 * @type String */
1799 Date.YEAR = "y";
1800
1801 /**
1802  * Provides a convenient method of performing basic date arithmetic.  This method
1803  * does not modify the Date instance being called - it creates and returns
1804  * a new Date instance containing the resulting date value.
1805  *
1806  * Examples:
1807  * <pre><code>
1808 //Basic usage:
1809 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1810 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1811
1812 //Negative values will subtract correctly:
1813 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1814 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1815
1816 //You can even chain several calls together in one line!
1817 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1818 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1819  </code></pre>
1820  *
1821  * @param {String} interval   A valid date interval enum value
1822  * @param {Number} value      The amount to add to the current date
1823  * @return {Date} The new Date instance
1824  */
1825 Date.prototype.add = function(interval, value){
1826   var d = this.clone();
1827   if (!interval || value === 0) { return d; }
1828   switch(interval.toLowerCase()){
1829     case Date.MILLI:
1830       d.setMilliseconds(this.getMilliseconds() + value);
1831       break;
1832     case Date.SECOND:
1833       d.setSeconds(this.getSeconds() + value);
1834       break;
1835     case Date.MINUTE:
1836       d.setMinutes(this.getMinutes() + value);
1837       break;
1838     case Date.HOUR:
1839       d.setHours(this.getHours() + value);
1840       break;
1841     case Date.DAY:
1842       d.setDate(this.getDate() + value);
1843       break;
1844     case Date.MONTH:
1845       var day = this.getDate();
1846       if(day > 28){
1847           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1848       }
1849       d.setDate(day);
1850       d.setMonth(this.getMonth() + value);
1851       break;
1852     case Date.YEAR:
1853       d.setFullYear(this.getFullYear() + value);
1854       break;
1855   }
1856   return d;
1857 };
1858 /*
1859  * Based on:
1860  * Ext JS Library 1.1.1
1861  * Copyright(c) 2006-2007, Ext JS, LLC.
1862  *
1863  * Originally Released Under LGPL - original licence link has changed is not relivant.
1864  *
1865  * Fork - LGPL
1866  * <script type="text/javascript">
1867  */
1868
1869 /**
1870  * @class Roo.lib.Dom
1871  * @static
1872  * 
1873  * Dom utils (from YIU afaik)
1874  * 
1875  **/
1876 Roo.lib.Dom = {
1877     /**
1878      * Get the view width
1879      * @param {Boolean} full True will get the full document, otherwise it's the view width
1880      * @return {Number} The width
1881      */
1882      
1883     getViewWidth : function(full) {
1884         return full ? this.getDocumentWidth() : this.getViewportWidth();
1885     },
1886     /**
1887      * Get the view height
1888      * @param {Boolean} full True will get the full document, otherwise it's the view height
1889      * @return {Number} The height
1890      */
1891     getViewHeight : function(full) {
1892         return full ? this.getDocumentHeight() : this.getViewportHeight();
1893     },
1894
1895     getDocumentHeight: function() {
1896         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1897         return Math.max(scrollHeight, this.getViewportHeight());
1898     },
1899
1900     getDocumentWidth: function() {
1901         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1902         return Math.max(scrollWidth, this.getViewportWidth());
1903     },
1904
1905     getViewportHeight: function() {
1906         var height = self.innerHeight;
1907         var mode = document.compatMode;
1908
1909         if ((mode || Roo.isIE) && !Roo.isOpera) {
1910             height = (mode == "CSS1Compat") ?
1911                      document.documentElement.clientHeight :
1912                      document.body.clientHeight;
1913         }
1914
1915         return height;
1916     },
1917
1918     getViewportWidth: function() {
1919         var width = self.innerWidth;
1920         var mode = document.compatMode;
1921
1922         if (mode || Roo.isIE) {
1923             width = (mode == "CSS1Compat") ?
1924                     document.documentElement.clientWidth :
1925                     document.body.clientWidth;
1926         }
1927         return width;
1928     },
1929
1930     isAncestor : function(p, c) {
1931         p = Roo.getDom(p);
1932         c = Roo.getDom(c);
1933         if (!p || !c) {
1934             return false;
1935         }
1936
1937         if (p.contains && !Roo.isSafari) {
1938             return p.contains(c);
1939         } else if (p.compareDocumentPosition) {
1940             return !!(p.compareDocumentPosition(c) & 16);
1941         } else {
1942             var parent = c.parentNode;
1943             while (parent) {
1944                 if (parent == p) {
1945                     return true;
1946                 }
1947                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1948                     return false;
1949                 }
1950                 parent = parent.parentNode;
1951             }
1952             return false;
1953         }
1954     },
1955
1956     getRegion : function(el) {
1957         return Roo.lib.Region.getRegion(el);
1958     },
1959
1960     getY : function(el) {
1961         return this.getXY(el)[1];
1962     },
1963
1964     getX : function(el) {
1965         return this.getXY(el)[0];
1966     },
1967
1968     getXY : function(el) {
1969         var p, pe, b, scroll, bd = document.body;
1970         el = Roo.getDom(el);
1971         var fly = Roo.lib.AnimBase.fly;
1972         if (el.getBoundingClientRect) {
1973             b = el.getBoundingClientRect();
1974             scroll = fly(document).getScroll();
1975             return [b.left + scroll.left, b.top + scroll.top];
1976         }
1977         var x = 0, y = 0;
1978
1979         p = el;
1980
1981         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1982
1983         while (p) {
1984
1985             x += p.offsetLeft;
1986             y += p.offsetTop;
1987
1988             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1989                 hasAbsolute = true;
1990             }
1991
1992             if (Roo.isGecko) {
1993                 pe = fly(p);
1994
1995                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1996                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1997
1998
1999                 x += bl;
2000                 y += bt;
2001
2002
2003                 if (p != el && pe.getStyle('overflow') != 'visible') {
2004                     x += bl;
2005                     y += bt;
2006                 }
2007             }
2008             p = p.offsetParent;
2009         }
2010
2011         if (Roo.isSafari && hasAbsolute) {
2012             x -= bd.offsetLeft;
2013             y -= bd.offsetTop;
2014         }
2015
2016         if (Roo.isGecko && !hasAbsolute) {
2017             var dbd = fly(bd);
2018             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2019             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2020         }
2021
2022         p = el.parentNode;
2023         while (p && p != bd) {
2024             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2025                 x -= p.scrollLeft;
2026                 y -= p.scrollTop;
2027             }
2028             p = p.parentNode;
2029         }
2030         return [x, y];
2031     },
2032  
2033   
2034
2035
2036     setXY : function(el, xy) {
2037         el = Roo.fly(el, '_setXY');
2038         el.position();
2039         var pts = el.translatePoints(xy);
2040         if (xy[0] !== false) {
2041             el.dom.style.left = pts.left + "px";
2042         }
2043         if (xy[1] !== false) {
2044             el.dom.style.top = pts.top + "px";
2045         }
2046     },
2047
2048     setX : function(el, x) {
2049         this.setXY(el, [x, false]);
2050     },
2051
2052     setY : function(el, y) {
2053         this.setXY(el, [false, y]);
2054     }
2055 };
2056 /*
2057  * Portions of this file are based on pieces of Yahoo User Interface Library
2058  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2059  * YUI licensed under the BSD License:
2060  * http://developer.yahoo.net/yui/license.txt
2061  * <script type="text/javascript">
2062  *
2063  */
2064
2065 Roo.lib.Event = function() {
2066     var loadComplete = false;
2067     var listeners = [];
2068     var unloadListeners = [];
2069     var retryCount = 0;
2070     var onAvailStack = [];
2071     var counter = 0;
2072     var lastError = null;
2073
2074     return {
2075         POLL_RETRYS: 200,
2076         POLL_INTERVAL: 20,
2077         EL: 0,
2078         TYPE: 1,
2079         FN: 2,
2080         WFN: 3,
2081         OBJ: 3,
2082         ADJ_SCOPE: 4,
2083         _interval: null,
2084
2085         startInterval: function() {
2086             if (!this._interval) {
2087                 var self = this;
2088                 var callback = function() {
2089                     self._tryPreloadAttach();
2090                 };
2091                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2092
2093             }
2094         },
2095
2096         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2097             onAvailStack.push({ id:         p_id,
2098                 fn:         p_fn,
2099                 obj:        p_obj,
2100                 override:   p_override,
2101                 checkReady: false    });
2102
2103             retryCount = this.POLL_RETRYS;
2104             this.startInterval();
2105         },
2106
2107
2108         addListener: function(el, eventName, fn) {
2109             el = Roo.getDom(el);
2110             if (!el || !fn) {
2111                 return false;
2112             }
2113
2114             if ("unload" == eventName) {
2115                 unloadListeners[unloadListeners.length] =
2116                 [el, eventName, fn];
2117                 return true;
2118             }
2119
2120             var wrappedFn = function(e) {
2121                 return fn(Roo.lib.Event.getEvent(e));
2122             };
2123
2124             var li = [el, eventName, fn, wrappedFn];
2125
2126             var index = listeners.length;
2127             listeners[index] = li;
2128
2129             this.doAdd(el, eventName, wrappedFn, false);
2130             return true;
2131
2132         },
2133
2134
2135         removeListener: function(el, eventName, fn) {
2136             var i, len;
2137
2138             el = Roo.getDom(el);
2139
2140             if(!fn) {
2141                 return this.purgeElement(el, false, eventName);
2142             }
2143
2144
2145             if ("unload" == eventName) {
2146
2147                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2148                     var li = unloadListeners[i];
2149                     if (li &&
2150                         li[0] == el &&
2151                         li[1] == eventName &&
2152                         li[2] == fn) {
2153                         unloadListeners.splice(i, 1);
2154                         return true;
2155                     }
2156                 }
2157
2158                 return false;
2159             }
2160
2161             var cacheItem = null;
2162
2163
2164             var index = arguments[3];
2165
2166             if ("undefined" == typeof index) {
2167                 index = this._getCacheIndex(el, eventName, fn);
2168             }
2169
2170             if (index >= 0) {
2171                 cacheItem = listeners[index];
2172             }
2173
2174             if (!el || !cacheItem) {
2175                 return false;
2176             }
2177
2178             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2179
2180             delete listeners[index][this.WFN];
2181             delete listeners[index][this.FN];
2182             listeners.splice(index, 1);
2183
2184             return true;
2185
2186         },
2187
2188
2189         getTarget: function(ev, resolveTextNode) {
2190             ev = ev.browserEvent || ev;
2191             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2192             var t = ev.target || ev.srcElement;
2193             return this.resolveTextNode(t);
2194         },
2195
2196
2197         resolveTextNode: function(node) {
2198             if (Roo.isSafari && node && 3 == node.nodeType) {
2199                 return node.parentNode;
2200             } else {
2201                 return node;
2202             }
2203         },
2204
2205
2206         getPageX: function(ev) {
2207             ev = ev.browserEvent || ev;
2208             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2209             var x = ev.pageX;
2210             if (!x && 0 !== x) {
2211                 x = ev.clientX || 0;
2212
2213                 if (Roo.isIE) {
2214                     x += this.getScroll()[1];
2215                 }
2216             }
2217
2218             return x;
2219         },
2220
2221
2222         getPageY: function(ev) {
2223             ev = ev.browserEvent || ev;
2224             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2225             var y = ev.pageY;
2226             if (!y && 0 !== y) {
2227                 y = ev.clientY || 0;
2228
2229                 if (Roo.isIE) {
2230                     y += this.getScroll()[0];
2231                 }
2232             }
2233
2234
2235             return y;
2236         },
2237
2238
2239         getXY: function(ev) {
2240             ev = ev.browserEvent || ev;
2241             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2242             return [this.getPageX(ev), this.getPageY(ev)];
2243         },
2244
2245
2246         getRelatedTarget: function(ev) {
2247             ev = ev.browserEvent || ev;
2248             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2249             var t = ev.relatedTarget;
2250             if (!t) {
2251                 if (ev.type == "mouseout") {
2252                     t = ev.toElement;
2253                 } else if (ev.type == "mouseover") {
2254                     t = ev.fromElement;
2255                 }
2256             }
2257
2258             return this.resolveTextNode(t);
2259         },
2260
2261
2262         getTime: function(ev) {
2263             ev = ev.browserEvent || ev;
2264             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2265             if (!ev.time) {
2266                 var t = new Date().getTime();
2267                 try {
2268                     ev.time = t;
2269                 } catch(ex) {
2270                     this.lastError = ex;
2271                     return t;
2272                 }
2273             }
2274
2275             return ev.time;
2276         },
2277
2278
2279         stopEvent: function(ev) {
2280             this.stopPropagation(ev);
2281             this.preventDefault(ev);
2282         },
2283
2284
2285         stopPropagation: function(ev) {
2286             ev = ev.browserEvent || ev;
2287             if (ev.stopPropagation) {
2288                 ev.stopPropagation();
2289             } else {
2290                 ev.cancelBubble = true;
2291             }
2292         },
2293
2294
2295         preventDefault: function(ev) {
2296             ev = ev.browserEvent || ev;
2297             if(ev.preventDefault) {
2298                 ev.preventDefault();
2299             } else {
2300                 ev.returnValue = false;
2301             }
2302         },
2303
2304
2305         getEvent: function(e) {
2306             var ev = e || window.event;
2307             if (!ev) {
2308                 var c = this.getEvent.caller;
2309                 while (c) {
2310                     ev = c.arguments[0];
2311                     if (ev && Event == ev.constructor) {
2312                         break;
2313                     }
2314                     c = c.caller;
2315                 }
2316             }
2317             return ev;
2318         },
2319
2320
2321         getCharCode: function(ev) {
2322             ev = ev.browserEvent || ev;
2323             return ev.charCode || ev.keyCode || 0;
2324         },
2325
2326
2327         _getCacheIndex: function(el, eventName, fn) {
2328             for (var i = 0,len = listeners.length; i < len; ++i) {
2329                 var li = listeners[i];
2330                 if (li &&
2331                     li[this.FN] == fn &&
2332                     li[this.EL] == el &&
2333                     li[this.TYPE] == eventName) {
2334                     return i;
2335                 }
2336             }
2337
2338             return -1;
2339         },
2340
2341
2342         elCache: {},
2343
2344
2345         getEl: function(id) {
2346             return document.getElementById(id);
2347         },
2348
2349
2350         clearCache: function() {
2351         },
2352
2353
2354         _load: function(e) {
2355             loadComplete = true;
2356             var EU = Roo.lib.Event;
2357
2358
2359             if (Roo.isIE) {
2360                 EU.doRemove(window, "load", EU._load);
2361             }
2362         },
2363
2364
2365         _tryPreloadAttach: function() {
2366
2367             if (this.locked) {
2368                 return false;
2369             }
2370
2371             this.locked = true;
2372
2373
2374             var tryAgain = !loadComplete;
2375             if (!tryAgain) {
2376                 tryAgain = (retryCount > 0);
2377             }
2378
2379
2380             var notAvail = [];
2381             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2382                 var item = onAvailStack[i];
2383                 if (item) {
2384                     var el = this.getEl(item.id);
2385
2386                     if (el) {
2387                         if (!item.checkReady ||
2388                             loadComplete ||
2389                             el.nextSibling ||
2390                             (document && document.body)) {
2391
2392                             var scope = el;
2393                             if (item.override) {
2394                                 if (item.override === true) {
2395                                     scope = item.obj;
2396                                 } else {
2397                                     scope = item.override;
2398                                 }
2399                             }
2400                             item.fn.call(scope, item.obj);
2401                             onAvailStack[i] = null;
2402                         }
2403                     } else {
2404                         notAvail.push(item);
2405                     }
2406                 }
2407             }
2408
2409             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2410
2411             if (tryAgain) {
2412
2413                 this.startInterval();
2414             } else {
2415                 clearInterval(this._interval);
2416                 this._interval = null;
2417             }
2418
2419             this.locked = false;
2420
2421             return true;
2422
2423         },
2424
2425
2426         purgeElement: function(el, recurse, eventName) {
2427             var elListeners = this.getListeners(el, eventName);
2428             if (elListeners) {
2429                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2430                     var l = elListeners[i];
2431                     this.removeListener(el, l.type, l.fn);
2432                 }
2433             }
2434
2435             if (recurse && el && el.childNodes) {
2436                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2437                     this.purgeElement(el.childNodes[i], recurse, eventName);
2438                 }
2439             }
2440         },
2441
2442
2443         getListeners: function(el, eventName) {
2444             var results = [], searchLists;
2445             if (!eventName) {
2446                 searchLists = [listeners, unloadListeners];
2447             } else if (eventName == "unload") {
2448                 searchLists = [unloadListeners];
2449             } else {
2450                 searchLists = [listeners];
2451             }
2452
2453             for (var j = 0; j < searchLists.length; ++j) {
2454                 var searchList = searchLists[j];
2455                 if (searchList && searchList.length > 0) {
2456                     for (var i = 0,len = searchList.length; i < len; ++i) {
2457                         var l = searchList[i];
2458                         if (l && l[this.EL] === el &&
2459                             (!eventName || eventName === l[this.TYPE])) {
2460                             results.push({
2461                                 type:   l[this.TYPE],
2462                                 fn:     l[this.FN],
2463                                 obj:    l[this.OBJ],
2464                                 adjust: l[this.ADJ_SCOPE],
2465                                 index:  i
2466                             });
2467                         }
2468                     }
2469                 }
2470             }
2471
2472             return (results.length) ? results : null;
2473         },
2474
2475
2476         _unload: function(e) {
2477
2478             var EU = Roo.lib.Event, i, j, l, len, index;
2479
2480             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2481                 l = unloadListeners[i];
2482                 if (l) {
2483                     var scope = window;
2484                     if (l[EU.ADJ_SCOPE]) {
2485                         if (l[EU.ADJ_SCOPE] === true) {
2486                             scope = l[EU.OBJ];
2487                         } else {
2488                             scope = l[EU.ADJ_SCOPE];
2489                         }
2490                     }
2491                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2492                     unloadListeners[i] = null;
2493                     l = null;
2494                     scope = null;
2495                 }
2496             }
2497
2498             unloadListeners = null;
2499
2500             if (listeners && listeners.length > 0) {
2501                 j = listeners.length;
2502                 while (j) {
2503                     index = j - 1;
2504                     l = listeners[index];
2505                     if (l) {
2506                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2507                                 l[EU.FN], index);
2508                     }
2509                     j = j - 1;
2510                 }
2511                 l = null;
2512
2513                 EU.clearCache();
2514             }
2515
2516             EU.doRemove(window, "unload", EU._unload);
2517
2518         },
2519
2520
2521         getScroll: function() {
2522             var dd = document.documentElement, db = document.body;
2523             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2524                 return [dd.scrollTop, dd.scrollLeft];
2525             } else if (db) {
2526                 return [db.scrollTop, db.scrollLeft];
2527             } else {
2528                 return [0, 0];
2529             }
2530         },
2531
2532
2533         doAdd: function () {
2534             if (window.addEventListener) {
2535                 return function(el, eventName, fn, capture) {
2536                     el.addEventListener(eventName, fn, (capture));
2537                 };
2538             } else if (window.attachEvent) {
2539                 return function(el, eventName, fn, capture) {
2540                     el.attachEvent("on" + eventName, fn);
2541                 };
2542             } else {
2543                 return function() {
2544                 };
2545             }
2546         }(),
2547
2548
2549         doRemove: function() {
2550             if (window.removeEventListener) {
2551                 return function (el, eventName, fn, capture) {
2552                     el.removeEventListener(eventName, fn, (capture));
2553                 };
2554             } else if (window.detachEvent) {
2555                 return function (el, eventName, fn) {
2556                     el.detachEvent("on" + eventName, fn);
2557                 };
2558             } else {
2559                 return function() {
2560                 };
2561             }
2562         }()
2563     };
2564     
2565 }();
2566 (function() {     
2567    
2568     var E = Roo.lib.Event;
2569     E.on = E.addListener;
2570     E.un = E.removeListener;
2571
2572     if (document && document.body) {
2573         E._load();
2574     } else {
2575         E.doAdd(window, "load", E._load);
2576     }
2577     E.doAdd(window, "unload", E._unload);
2578     E._tryPreloadAttach();
2579 })();
2580
2581 /*
2582  * Portions of this file are based on pieces of Yahoo User Interface Library
2583  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2584  * YUI licensed under the BSD License:
2585  * http://developer.yahoo.net/yui/license.txt
2586  * <script type="text/javascript">
2587  *
2588  */
2589
2590 (function() {
2591     /**
2592      * @class Roo.lib.Ajax
2593      *
2594      */
2595     Roo.lib.Ajax = {
2596         /**
2597          * @static 
2598          */
2599         request : function(method, uri, cb, data, options) {
2600             if(options){
2601                 var hs = options.headers;
2602                 if(hs){
2603                     for(var h in hs){
2604                         if(hs.hasOwnProperty(h)){
2605                             this.initHeader(h, hs[h], false);
2606                         }
2607                     }
2608                 }
2609                 if(options.xmlData){
2610                     this.initHeader('Content-Type', 'text/xml', false);
2611                     method = 'POST';
2612                     data = options.xmlData;
2613                 }
2614             }
2615
2616             return this.asyncRequest(method, uri, cb, data);
2617         },
2618
2619         serializeForm : function(form) {
2620             if(typeof form == 'string') {
2621                 form = (document.getElementById(form) || document.forms[form]);
2622             }
2623
2624             var el, name, val, disabled, data = '', hasSubmit = false;
2625             for (var i = 0; i < form.elements.length; i++) {
2626                 el = form.elements[i];
2627                 disabled = form.elements[i].disabled;
2628                 name = form.elements[i].name;
2629                 val = form.elements[i].value;
2630
2631                 if (!disabled && name){
2632                     switch (el.type)
2633                             {
2634                         case 'select-one':
2635                         case 'select-multiple':
2636                             for (var j = 0; j < el.options.length; j++) {
2637                                 if (el.options[j].selected) {
2638                                     if (Roo.isIE) {
2639                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2640                                     }
2641                                     else {
2642                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2643                                     }
2644                                 }
2645                             }
2646                             break;
2647                         case 'radio':
2648                         case 'checkbox':
2649                             if (el.checked) {
2650                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2651                             }
2652                             break;
2653                         case 'file':
2654
2655                         case undefined:
2656
2657                         case 'reset':
2658
2659                         case 'button':
2660
2661                             break;
2662                         case 'submit':
2663                             if(hasSubmit == false) {
2664                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2665                                 hasSubmit = true;
2666                             }
2667                             break;
2668                         default:
2669                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2670                             break;
2671                     }
2672                 }
2673             }
2674             data = data.substr(0, data.length - 1);
2675             return data;
2676         },
2677
2678         headers:{},
2679
2680         hasHeaders:false,
2681
2682         useDefaultHeader:true,
2683
2684         defaultPostHeader:'application/x-www-form-urlencoded',
2685
2686         useDefaultXhrHeader:true,
2687
2688         defaultXhrHeader:'XMLHttpRequest',
2689
2690         hasDefaultHeaders:true,
2691
2692         defaultHeaders:{},
2693
2694         poll:{},
2695
2696         timeout:{},
2697
2698         pollInterval:50,
2699
2700         transactionId:0,
2701
2702         setProgId:function(id)
2703         {
2704             this.activeX.unshift(id);
2705         },
2706
2707         setDefaultPostHeader:function(b)
2708         {
2709             this.useDefaultHeader = b;
2710         },
2711
2712         setDefaultXhrHeader:function(b)
2713         {
2714             this.useDefaultXhrHeader = b;
2715         },
2716
2717         setPollingInterval:function(i)
2718         {
2719             if (typeof i == 'number' && isFinite(i)) {
2720                 this.pollInterval = i;
2721             }
2722         },
2723
2724         createXhrObject:function(transactionId)
2725         {
2726             var obj,http;
2727             try
2728             {
2729
2730                 http = new XMLHttpRequest();
2731
2732                 obj = { conn:http, tId:transactionId };
2733             }
2734             catch(e)
2735             {
2736                 for (var i = 0; i < this.activeX.length; ++i) {
2737                     try
2738                     {
2739
2740                         http = new ActiveXObject(this.activeX[i]);
2741
2742                         obj = { conn:http, tId:transactionId };
2743                         break;
2744                     }
2745                     catch(e) {
2746                     }
2747                 }
2748             }
2749             finally
2750             {
2751                 return obj;
2752             }
2753         },
2754
2755         getConnectionObject:function()
2756         {
2757             var o;
2758             var tId = this.transactionId;
2759
2760             try
2761             {
2762                 o = this.createXhrObject(tId);
2763                 if (o) {
2764                     this.transactionId++;
2765                 }
2766             }
2767             catch(e) {
2768             }
2769             finally
2770             {
2771                 return o;
2772             }
2773         },
2774
2775         asyncRequest:function(method, uri, callback, postData)
2776         {
2777             var o = this.getConnectionObject();
2778
2779             if (!o) {
2780                 return null;
2781             }
2782             else {
2783                 o.conn.open(method, uri, true);
2784
2785                 if (this.useDefaultXhrHeader) {
2786                     if (!this.defaultHeaders['X-Requested-With']) {
2787                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2788                     }
2789                 }
2790
2791                 if(postData && this.useDefaultHeader){
2792                     this.initHeader('Content-Type', this.defaultPostHeader);
2793                 }
2794
2795                  if (this.hasDefaultHeaders || this.hasHeaders) {
2796                     this.setHeader(o);
2797                 }
2798
2799                 this.handleReadyState(o, callback);
2800                 o.conn.send(postData || null);
2801
2802                 return o;
2803             }
2804         },
2805
2806         handleReadyState:function(o, callback)
2807         {
2808             var oConn = this;
2809
2810             if (callback && callback.timeout) {
2811                 
2812                 this.timeout[o.tId] = window.setTimeout(function() {
2813                     oConn.abort(o, callback, true);
2814                 }, callback.timeout);
2815             }
2816
2817             this.poll[o.tId] = window.setInterval(
2818                     function() {
2819                         if (o.conn && o.conn.readyState == 4) {
2820                             window.clearInterval(oConn.poll[o.tId]);
2821                             delete oConn.poll[o.tId];
2822
2823                             if(callback && callback.timeout) {
2824                                 window.clearTimeout(oConn.timeout[o.tId]);
2825                                 delete oConn.timeout[o.tId];
2826                             }
2827
2828                             oConn.handleTransactionResponse(o, callback);
2829                         }
2830                     }
2831                     , this.pollInterval);
2832         },
2833
2834         handleTransactionResponse:function(o, callback, isAbort)
2835         {
2836
2837             if (!callback) {
2838                 this.releaseObject(o);
2839                 return;
2840             }
2841
2842             var httpStatus, responseObject;
2843
2844             try
2845             {
2846                 if (o.conn.status !== undefined && o.conn.status != 0) {
2847                     httpStatus = o.conn.status;
2848                 }
2849                 else {
2850                     httpStatus = 13030;
2851                 }
2852             }
2853             catch(e) {
2854
2855
2856                 httpStatus = 13030;
2857             }
2858
2859             if (httpStatus >= 200 && httpStatus < 300) {
2860                 responseObject = this.createResponseObject(o, callback.argument);
2861                 if (callback.success) {
2862                     if (!callback.scope) {
2863                         callback.success(responseObject);
2864                     }
2865                     else {
2866
2867
2868                         callback.success.apply(callback.scope, [responseObject]);
2869                     }
2870                 }
2871             }
2872             else {
2873                 switch (httpStatus) {
2874
2875                     case 12002:
2876                     case 12029:
2877                     case 12030:
2878                     case 12031:
2879                     case 12152:
2880                     case 13030:
2881                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2882                         if (callback.failure) {
2883                             if (!callback.scope) {
2884                                 callback.failure(responseObject);
2885                             }
2886                             else {
2887                                 callback.failure.apply(callback.scope, [responseObject]);
2888                             }
2889                         }
2890                         break;
2891                     default:
2892                         responseObject = this.createResponseObject(o, callback.argument);
2893                         if (callback.failure) {
2894                             if (!callback.scope) {
2895                                 callback.failure(responseObject);
2896                             }
2897                             else {
2898                                 callback.failure.apply(callback.scope, [responseObject]);
2899                             }
2900                         }
2901                 }
2902             }
2903
2904             this.releaseObject(o);
2905             responseObject = null;
2906         },
2907
2908         createResponseObject:function(o, callbackArg)
2909         {
2910             var obj = {};
2911             var headerObj = {};
2912
2913             try
2914             {
2915                 var headerStr = o.conn.getAllResponseHeaders();
2916                 var header = headerStr.split('\n');
2917                 for (var i = 0; i < header.length; i++) {
2918                     var delimitPos = header[i].indexOf(':');
2919                     if (delimitPos != -1) {
2920                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2921                     }
2922                 }
2923             }
2924             catch(e) {
2925             }
2926
2927             obj.tId = o.tId;
2928             obj.status = o.conn.status;
2929             obj.statusText = o.conn.statusText;
2930             obj.getResponseHeader = headerObj;
2931             obj.getAllResponseHeaders = headerStr;
2932             obj.responseText = o.conn.responseText;
2933             obj.responseXML = o.conn.responseXML;
2934
2935             if (typeof callbackArg !== undefined) {
2936                 obj.argument = callbackArg;
2937             }
2938
2939             return obj;
2940         },
2941
2942         createExceptionObject:function(tId, callbackArg, isAbort)
2943         {
2944             var COMM_CODE = 0;
2945             var COMM_ERROR = 'communication failure';
2946             var ABORT_CODE = -1;
2947             var ABORT_ERROR = 'transaction aborted';
2948
2949             var obj = {};
2950
2951             obj.tId = tId;
2952             if (isAbort) {
2953                 obj.status = ABORT_CODE;
2954                 obj.statusText = ABORT_ERROR;
2955             }
2956             else {
2957                 obj.status = COMM_CODE;
2958                 obj.statusText = COMM_ERROR;
2959             }
2960
2961             if (callbackArg) {
2962                 obj.argument = callbackArg;
2963             }
2964
2965             return obj;
2966         },
2967
2968         initHeader:function(label, value, isDefault)
2969         {
2970             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2971
2972             if (headerObj[label] === undefined) {
2973                 headerObj[label] = value;
2974             }
2975             else {
2976
2977
2978                 headerObj[label] = value + "," + headerObj[label];
2979             }
2980
2981             if (isDefault) {
2982                 this.hasDefaultHeaders = true;
2983             }
2984             else {
2985                 this.hasHeaders = true;
2986             }
2987         },
2988
2989
2990         setHeader:function(o)
2991         {
2992             if (this.hasDefaultHeaders) {
2993                 for (var prop in this.defaultHeaders) {
2994                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2995                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2996                     }
2997                 }
2998             }
2999
3000             if (this.hasHeaders) {
3001                 for (var prop in this.headers) {
3002                     if (this.headers.hasOwnProperty(prop)) {
3003                         o.conn.setRequestHeader(prop, this.headers[prop]);
3004                     }
3005                 }
3006                 this.headers = {};
3007                 this.hasHeaders = false;
3008             }
3009         },
3010
3011         resetDefaultHeaders:function() {
3012             delete this.defaultHeaders;
3013             this.defaultHeaders = {};
3014             this.hasDefaultHeaders = false;
3015         },
3016
3017         abort:function(o, callback, isTimeout)
3018         {
3019             if(this.isCallInProgress(o)) {
3020                 o.conn.abort();
3021                 window.clearInterval(this.poll[o.tId]);
3022                 delete this.poll[o.tId];
3023                 if (isTimeout) {
3024                     delete this.timeout[o.tId];
3025                 }
3026
3027                 this.handleTransactionResponse(o, callback, true);
3028
3029                 return true;
3030             }
3031             else {
3032                 return false;
3033             }
3034         },
3035
3036
3037         isCallInProgress:function(o)
3038         {
3039             if (o && o.conn) {
3040                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3041             }
3042             else {
3043
3044                 return false;
3045             }
3046         },
3047
3048
3049         releaseObject:function(o)
3050         {
3051
3052             o.conn = null;
3053
3054             o = null;
3055         },
3056
3057         activeX:[
3058         'MSXML2.XMLHTTP.3.0',
3059         'MSXML2.XMLHTTP',
3060         'Microsoft.XMLHTTP'
3061         ]
3062
3063
3064     };
3065 })();/*
3066  * Portions of this file are based on pieces of Yahoo User Interface Library
3067  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3068  * YUI licensed under the BSD License:
3069  * http://developer.yahoo.net/yui/license.txt
3070  * <script type="text/javascript">
3071  *
3072  */
3073
3074 Roo.lib.Region = function(t, r, b, l) {
3075     this.top = t;
3076     this[1] = t;
3077     this.right = r;
3078     this.bottom = b;
3079     this.left = l;
3080     this[0] = l;
3081 };
3082
3083
3084 Roo.lib.Region.prototype = {
3085     contains : function(region) {
3086         return ( region.left >= this.left &&
3087                  region.right <= this.right &&
3088                  region.top >= this.top &&
3089                  region.bottom <= this.bottom    );
3090
3091     },
3092
3093     getArea : function() {
3094         return ( (this.bottom - this.top) * (this.right - this.left) );
3095     },
3096
3097     intersect : function(region) {
3098         var t = Math.max(this.top, region.top);
3099         var r = Math.min(this.right, region.right);
3100         var b = Math.min(this.bottom, region.bottom);
3101         var l = Math.max(this.left, region.left);
3102
3103         if (b >= t && r >= l) {
3104             return new Roo.lib.Region(t, r, b, l);
3105         } else {
3106             return null;
3107         }
3108     },
3109     union : function(region) {
3110         var t = Math.min(this.top, region.top);
3111         var r = Math.max(this.right, region.right);
3112         var b = Math.max(this.bottom, region.bottom);
3113         var l = Math.min(this.left, region.left);
3114
3115         return new Roo.lib.Region(t, r, b, l);
3116     },
3117
3118     adjust : function(t, l, b, r) {
3119         this.top += t;
3120         this.left += l;
3121         this.right += r;
3122         this.bottom += b;
3123         return this;
3124     }
3125 };
3126
3127 Roo.lib.Region.getRegion = function(el) {
3128     var p = Roo.lib.Dom.getXY(el);
3129
3130     var t = p[1];
3131     var r = p[0] + el.offsetWidth;
3132     var b = p[1] + el.offsetHeight;
3133     var l = p[0];
3134
3135     return new Roo.lib.Region(t, r, b, l);
3136 };
3137 /*
3138  * Portions of this file are based on pieces of Yahoo User Interface Library
3139  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3140  * YUI licensed under the BSD License:
3141  * http://developer.yahoo.net/yui/license.txt
3142  * <script type="text/javascript">
3143  *
3144  */
3145 //@@dep Roo.lib.Region
3146
3147
3148 Roo.lib.Point = function(x, y) {
3149     if (x instanceof Array) {
3150         y = x[1];
3151         x = x[0];
3152     }
3153     this.x = this.right = this.left = this[0] = x;
3154     this.y = this.top = this.bottom = this[1] = y;
3155 };
3156
3157 Roo.lib.Point.prototype = new Roo.lib.Region();
3158 /*
3159  * Portions of this file are based on pieces of Yahoo User Interface Library
3160  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3161  * YUI licensed under the BSD License:
3162  * http://developer.yahoo.net/yui/license.txt
3163  * <script type="text/javascript">
3164  *
3165  */
3166  
3167 (function() {   
3168
3169     Roo.lib.Anim = {
3170         scroll : function(el, args, duration, easing, cb, scope) {
3171             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3172         },
3173
3174         motion : function(el, args, duration, easing, cb, scope) {
3175             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3176         },
3177
3178         color : function(el, args, duration, easing, cb, scope) {
3179             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3180         },
3181
3182         run : function(el, args, duration, easing, cb, scope, type) {
3183             type = type || Roo.lib.AnimBase;
3184             if (typeof easing == "string") {
3185                 easing = Roo.lib.Easing[easing];
3186             }
3187             var anim = new type(el, args, duration, easing);
3188             anim.animateX(function() {
3189                 Roo.callback(cb, scope);
3190             });
3191             return anim;
3192         }
3193     };
3194 })();/*
3195  * Portions of this file are based on pieces of Yahoo User Interface Library
3196  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3197  * YUI licensed under the BSD License:
3198  * http://developer.yahoo.net/yui/license.txt
3199  * <script type="text/javascript">
3200  *
3201  */
3202
3203 (function() {    
3204     var libFlyweight;
3205     
3206     function fly(el) {
3207         if (!libFlyweight) {
3208             libFlyweight = new Roo.Element.Flyweight();
3209         }
3210         libFlyweight.dom = el;
3211         return libFlyweight;
3212     }
3213
3214     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3215     
3216    
3217     
3218     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3219         if (el) {
3220             this.init(el, attributes, duration, method);
3221         }
3222     };
3223
3224     Roo.lib.AnimBase.fly = fly;
3225     
3226     
3227     
3228     Roo.lib.AnimBase.prototype = {
3229
3230         toString: function() {
3231             var el = this.getEl();
3232             var id = el.id || el.tagName;
3233             return ("Anim " + id);
3234         },
3235
3236         patterns: {
3237             noNegatives:        /width|height|opacity|padding/i,
3238             offsetAttribute:  /^((width|height)|(top|left))$/,
3239             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3240             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3241         },
3242
3243
3244         doMethod: function(attr, start, end) {
3245             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3246         },
3247
3248
3249         setAttribute: function(attr, val, unit) {
3250             if (this.patterns.noNegatives.test(attr)) {
3251                 val = (val > 0) ? val : 0;
3252             }
3253
3254             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3255         },
3256
3257
3258         getAttribute: function(attr) {
3259             var el = this.getEl();
3260             var val = fly(el).getStyle(attr);
3261
3262             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3263                 return parseFloat(val);
3264             }
3265
3266             var a = this.patterns.offsetAttribute.exec(attr) || [];
3267             var pos = !!( a[3] );
3268             var box = !!( a[2] );
3269
3270
3271             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3272                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3273             } else {
3274                 val = 0;
3275             }
3276
3277             return val;
3278         },
3279
3280
3281         getDefaultUnit: function(attr) {
3282             if (this.patterns.defaultUnit.test(attr)) {
3283                 return 'px';
3284             }
3285
3286             return '';
3287         },
3288
3289         animateX : function(callback, scope) {
3290             var f = function() {
3291                 this.onComplete.removeListener(f);
3292                 if (typeof callback == "function") {
3293                     callback.call(scope || this, this);
3294                 }
3295             };
3296             this.onComplete.addListener(f, this);
3297             this.animate();
3298         },
3299
3300
3301         setRuntimeAttribute: function(attr) {
3302             var start;
3303             var end;
3304             var attributes = this.attributes;
3305
3306             this.runtimeAttributes[attr] = {};
3307
3308             var isset = function(prop) {
3309                 return (typeof prop !== 'undefined');
3310             };
3311
3312             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3313                 return false;
3314             }
3315
3316             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3317
3318
3319             if (isset(attributes[attr]['to'])) {
3320                 end = attributes[attr]['to'];
3321             } else if (isset(attributes[attr]['by'])) {
3322                 if (start.constructor == Array) {
3323                     end = [];
3324                     for (var i = 0, len = start.length; i < len; ++i) {
3325                         end[i] = start[i] + attributes[attr]['by'][i];
3326                     }
3327                 } else {
3328                     end = start + attributes[attr]['by'];
3329                 }
3330             }
3331
3332             this.runtimeAttributes[attr].start = start;
3333             this.runtimeAttributes[attr].end = end;
3334
3335
3336             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3337         },
3338
3339
3340         init: function(el, attributes, duration, method) {
3341
3342             var isAnimated = false;
3343
3344
3345             var startTime = null;
3346
3347
3348             var actualFrames = 0;
3349
3350
3351             el = Roo.getDom(el);
3352
3353
3354             this.attributes = attributes || {};
3355
3356
3357             this.duration = duration || 1;
3358
3359
3360             this.method = method || Roo.lib.Easing.easeNone;
3361
3362
3363             this.useSeconds = true;
3364
3365
3366             this.currentFrame = 0;
3367
3368
3369             this.totalFrames = Roo.lib.AnimMgr.fps;
3370
3371
3372             this.getEl = function() {
3373                 return el;
3374             };
3375
3376
3377             this.isAnimated = function() {
3378                 return isAnimated;
3379             };
3380
3381
3382             this.getStartTime = function() {
3383                 return startTime;
3384             };
3385
3386             this.runtimeAttributes = {};
3387
3388
3389             this.animate = function() {
3390                 if (this.isAnimated()) {
3391                     return false;
3392                 }
3393
3394                 this.currentFrame = 0;
3395
3396                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3397
3398                 Roo.lib.AnimMgr.registerElement(this);
3399             };
3400
3401
3402             this.stop = function(finish) {
3403                 if (finish) {
3404                     this.currentFrame = this.totalFrames;
3405                     this._onTween.fire();
3406                 }
3407                 Roo.lib.AnimMgr.stop(this);
3408             };
3409
3410             var onStart = function() {
3411                 this.onStart.fire();
3412
3413                 this.runtimeAttributes = {};
3414                 for (var attr in this.attributes) {
3415                     this.setRuntimeAttribute(attr);
3416                 }
3417
3418                 isAnimated = true;
3419                 actualFrames = 0;
3420                 startTime = new Date();
3421             };
3422
3423
3424             var onTween = function() {
3425                 var data = {
3426                     duration: new Date() - this.getStartTime(),
3427                     currentFrame: this.currentFrame
3428                 };
3429
3430                 data.toString = function() {
3431                     return (
3432                             'duration: ' + data.duration +
3433                             ', currentFrame: ' + data.currentFrame
3434                             );
3435                 };
3436
3437                 this.onTween.fire(data);
3438
3439                 var runtimeAttributes = this.runtimeAttributes;
3440
3441                 for (var attr in runtimeAttributes) {
3442                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3443                 }
3444
3445                 actualFrames += 1;
3446             };
3447
3448             var onComplete = function() {
3449                 var actual_duration = (new Date() - startTime) / 1000 ;
3450
3451                 var data = {
3452                     duration: actual_duration,
3453                     frames: actualFrames,
3454                     fps: actualFrames / actual_duration
3455                 };
3456
3457                 data.toString = function() {
3458                     return (
3459                             'duration: ' + data.duration +
3460                             ', frames: ' + data.frames +
3461                             ', fps: ' + data.fps
3462                             );
3463                 };
3464
3465                 isAnimated = false;
3466                 actualFrames = 0;
3467                 this.onComplete.fire(data);
3468             };
3469
3470
3471             this._onStart = new Roo.util.Event(this);
3472             this.onStart = new Roo.util.Event(this);
3473             this.onTween = new Roo.util.Event(this);
3474             this._onTween = new Roo.util.Event(this);
3475             this.onComplete = new Roo.util.Event(this);
3476             this._onComplete = new Roo.util.Event(this);
3477             this._onStart.addListener(onStart);
3478             this._onTween.addListener(onTween);
3479             this._onComplete.addListener(onComplete);
3480         }
3481     };
3482 })();
3483 /*
3484  * Portions of this file are based on pieces of Yahoo User Interface Library
3485  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3486  * YUI licensed under the BSD License:
3487  * http://developer.yahoo.net/yui/license.txt
3488  * <script type="text/javascript">
3489  *
3490  */
3491
3492 Roo.lib.AnimMgr = new function() {
3493
3494     var thread = null;
3495
3496
3497     var queue = [];
3498
3499
3500     var tweenCount = 0;
3501
3502
3503     this.fps = 1000;
3504
3505
3506     this.delay = 1;
3507
3508
3509     this.registerElement = function(tween) {
3510         queue[queue.length] = tween;
3511         tweenCount += 1;
3512         tween._onStart.fire();
3513         this.start();
3514     };
3515
3516
3517     this.unRegister = function(tween, index) {
3518         tween._onComplete.fire();
3519         index = index || getIndex(tween);
3520         if (index != -1) {
3521             queue.splice(index, 1);
3522         }
3523
3524         tweenCount -= 1;
3525         if (tweenCount <= 0) {
3526             this.stop();
3527         }
3528     };
3529
3530
3531     this.start = function() {
3532         if (thread === null) {
3533             thread = setInterval(this.run, this.delay);
3534         }
3535     };
3536
3537
3538     this.stop = function(tween) {
3539         if (!tween) {
3540             clearInterval(thread);
3541
3542             for (var i = 0, len = queue.length; i < len; ++i) {
3543                 if (queue[0].isAnimated()) {
3544                     this.unRegister(queue[0], 0);
3545                 }
3546             }
3547
3548             queue = [];
3549             thread = null;
3550             tweenCount = 0;
3551         }
3552         else {
3553             this.unRegister(tween);
3554         }
3555     };
3556
3557
3558     this.run = function() {
3559         for (var i = 0, len = queue.length; i < len; ++i) {
3560             var tween = queue[i];
3561             if (!tween || !tween.isAnimated()) {
3562                 continue;
3563             }
3564
3565             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3566             {
3567                 tween.currentFrame += 1;
3568
3569                 if (tween.useSeconds) {
3570                     correctFrame(tween);
3571                 }
3572                 tween._onTween.fire();
3573             }
3574             else {
3575                 Roo.lib.AnimMgr.stop(tween, i);
3576             }
3577         }
3578     };
3579
3580     var getIndex = function(anim) {
3581         for (var i = 0, len = queue.length; i < len; ++i) {
3582             if (queue[i] == anim) {
3583                 return i;
3584             }
3585         }
3586         return -1;
3587     };
3588
3589
3590     var correctFrame = function(tween) {
3591         var frames = tween.totalFrames;
3592         var frame = tween.currentFrame;
3593         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3594         var elapsed = (new Date() - tween.getStartTime());
3595         var tweak = 0;
3596
3597         if (elapsed < tween.duration * 1000) {
3598             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3599         } else {
3600             tweak = frames - (frame + 1);
3601         }
3602         if (tweak > 0 && isFinite(tweak)) {
3603             if (tween.currentFrame + tweak >= frames) {
3604                 tweak = frames - (frame + 1);
3605             }
3606
3607             tween.currentFrame += tweak;
3608         }
3609     };
3610 };
3611
3612     /*
3613  * Portions of this file are based on pieces of Yahoo User Interface Library
3614  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3615  * YUI licensed under the BSD License:
3616  * http://developer.yahoo.net/yui/license.txt
3617  * <script type="text/javascript">
3618  *
3619  */
3620 Roo.lib.Bezier = new function() {
3621
3622         this.getPosition = function(points, t) {
3623             var n = points.length;
3624             var tmp = [];
3625
3626             for (var i = 0; i < n; ++i) {
3627                 tmp[i] = [points[i][0], points[i][1]];
3628             }
3629
3630             for (var j = 1; j < n; ++j) {
3631                 for (i = 0; i < n - j; ++i) {
3632                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3633                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3634                 }
3635             }
3636
3637             return [ tmp[0][0], tmp[0][1] ];
3638
3639         };
3640     };/*
3641  * Portions of this file are based on pieces of Yahoo User Interface Library
3642  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3643  * YUI licensed under the BSD License:
3644  * http://developer.yahoo.net/yui/license.txt
3645  * <script type="text/javascript">
3646  *
3647  */
3648 (function() {
3649
3650     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3651         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3652     };
3653
3654     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3655
3656     var fly = Roo.lib.AnimBase.fly;
3657     var Y = Roo.lib;
3658     var superclass = Y.ColorAnim.superclass;
3659     var proto = Y.ColorAnim.prototype;
3660
3661     proto.toString = function() {
3662         var el = this.getEl();
3663         var id = el.id || el.tagName;
3664         return ("ColorAnim " + id);
3665     };
3666
3667     proto.patterns.color = /color$/i;
3668     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3669     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3670     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3671     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3672
3673
3674     proto.parseColor = function(s) {
3675         if (s.length == 3) {
3676             return s;
3677         }
3678
3679         var c = this.patterns.hex.exec(s);
3680         if (c && c.length == 4) {
3681             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3682         }
3683
3684         c = this.patterns.rgb.exec(s);
3685         if (c && c.length == 4) {
3686             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3687         }
3688
3689         c = this.patterns.hex3.exec(s);
3690         if (c && c.length == 4) {
3691             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3692         }
3693
3694         return null;
3695     };
3696     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3697     proto.getAttribute = function(attr) {
3698         var el = this.getEl();
3699         if (this.patterns.color.test(attr)) {
3700             var val = fly(el).getStyle(attr);
3701
3702             if (this.patterns.transparent.test(val)) {
3703                 var parent = el.parentNode;
3704                 val = fly(parent).getStyle(attr);
3705
3706                 while (parent && this.patterns.transparent.test(val)) {
3707                     parent = parent.parentNode;
3708                     val = fly(parent).getStyle(attr);
3709                     if (parent.tagName.toUpperCase() == 'HTML') {
3710                         val = '#fff';
3711                     }
3712                 }
3713             }
3714         } else {
3715             val = superclass.getAttribute.call(this, attr);
3716         }
3717
3718         return val;
3719     };
3720     proto.getAttribute = function(attr) {
3721         var el = this.getEl();
3722         if (this.patterns.color.test(attr)) {
3723             var val = fly(el).getStyle(attr);
3724
3725             if (this.patterns.transparent.test(val)) {
3726                 var parent = el.parentNode;
3727                 val = fly(parent).getStyle(attr);
3728
3729                 while (parent && this.patterns.transparent.test(val)) {
3730                     parent = parent.parentNode;
3731                     val = fly(parent).getStyle(attr);
3732                     if (parent.tagName.toUpperCase() == 'HTML') {
3733                         val = '#fff';
3734                     }
3735                 }
3736             }
3737         } else {
3738             val = superclass.getAttribute.call(this, attr);
3739         }
3740
3741         return val;
3742     };
3743
3744     proto.doMethod = function(attr, start, end) {
3745         var val;
3746
3747         if (this.patterns.color.test(attr)) {
3748             val = [];
3749             for (var i = 0, len = start.length; i < len; ++i) {
3750                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3751             }
3752
3753             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3754         }
3755         else {
3756             val = superclass.doMethod.call(this, attr, start, end);
3757         }
3758
3759         return val;
3760     };
3761
3762     proto.setRuntimeAttribute = function(attr) {
3763         superclass.setRuntimeAttribute.call(this, attr);
3764
3765         if (this.patterns.color.test(attr)) {
3766             var attributes = this.attributes;
3767             var start = this.parseColor(this.runtimeAttributes[attr].start);
3768             var end = this.parseColor(this.runtimeAttributes[attr].end);
3769
3770             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3771                 end = this.parseColor(attributes[attr].by);
3772
3773                 for (var i = 0, len = start.length; i < len; ++i) {
3774                     end[i] = start[i] + end[i];
3775                 }
3776             }
3777
3778             this.runtimeAttributes[attr].start = start;
3779             this.runtimeAttributes[attr].end = end;
3780         }
3781     };
3782 })();
3783
3784 /*
3785  * Portions of this file are based on pieces of Yahoo User Interface Library
3786  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3787  * YUI licensed under the BSD License:
3788  * http://developer.yahoo.net/yui/license.txt
3789  * <script type="text/javascript">
3790  *
3791  */
3792 Roo.lib.Easing = {
3793
3794
3795     easeNone: function (t, b, c, d) {
3796         return c * t / d + b;
3797     },
3798
3799
3800     easeIn: function (t, b, c, d) {
3801         return c * (t /= d) * t + b;
3802     },
3803
3804
3805     easeOut: function (t, b, c, d) {
3806         return -c * (t /= d) * (t - 2) + b;
3807     },
3808
3809
3810     easeBoth: function (t, b, c, d) {
3811         if ((t /= d / 2) < 1) {
3812             return c / 2 * t * t + b;
3813         }
3814
3815         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3816     },
3817
3818
3819     easeInStrong: function (t, b, c, d) {
3820         return c * (t /= d) * t * t * t + b;
3821     },
3822
3823
3824     easeOutStrong: function (t, b, c, d) {
3825         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3826     },
3827
3828
3829     easeBothStrong: function (t, b, c, d) {
3830         if ((t /= d / 2) < 1) {
3831             return c / 2 * t * t * t * t + b;
3832         }
3833
3834         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3835     },
3836
3837
3838
3839     elasticIn: function (t, b, c, d, a, p) {
3840         if (t == 0) {
3841             return b;
3842         }
3843         if ((t /= d) == 1) {
3844             return b + c;
3845         }
3846         if (!p) {
3847             p = d * .3;
3848         }
3849
3850         if (!a || a < Math.abs(c)) {
3851             a = c;
3852             var s = p / 4;
3853         }
3854         else {
3855             var s = p / (2 * Math.PI) * Math.asin(c / a);
3856         }
3857
3858         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3859     },
3860
3861
3862     elasticOut: function (t, b, c, d, a, p) {
3863         if (t == 0) {
3864             return b;
3865         }
3866         if ((t /= d) == 1) {
3867             return b + c;
3868         }
3869         if (!p) {
3870             p = d * .3;
3871         }
3872
3873         if (!a || a < Math.abs(c)) {
3874             a = c;
3875             var s = p / 4;
3876         }
3877         else {
3878             var s = p / (2 * Math.PI) * Math.asin(c / a);
3879         }
3880
3881         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3882     },
3883
3884
3885     elasticBoth: function (t, b, c, d, a, p) {
3886         if (t == 0) {
3887             return b;
3888         }
3889
3890         if ((t /= d / 2) == 2) {
3891             return b + c;
3892         }
3893
3894         if (!p) {
3895             p = d * (.3 * 1.5);
3896         }
3897
3898         if (!a || a < Math.abs(c)) {
3899             a = c;
3900             var s = p / 4;
3901         }
3902         else {
3903             var s = p / (2 * Math.PI) * Math.asin(c / a);
3904         }
3905
3906         if (t < 1) {
3907             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3908                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3909         }
3910         return a * Math.pow(2, -10 * (t -= 1)) *
3911                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3912     },
3913
3914
3915
3916     backIn: function (t, b, c, d, s) {
3917         if (typeof s == 'undefined') {
3918             s = 1.70158;
3919         }
3920         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3921     },
3922
3923
3924     backOut: function (t, b, c, d, s) {
3925         if (typeof s == 'undefined') {
3926             s = 1.70158;
3927         }
3928         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3929     },
3930
3931
3932     backBoth: function (t, b, c, d, s) {
3933         if (typeof s == 'undefined') {
3934             s = 1.70158;
3935         }
3936
3937         if ((t /= d / 2 ) < 1) {
3938             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3939         }
3940         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3941     },
3942
3943
3944     bounceIn: function (t, b, c, d) {
3945         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3946     },
3947
3948
3949     bounceOut: function (t, b, c, d) {
3950         if ((t /= d) < (1 / 2.75)) {
3951             return c * (7.5625 * t * t) + b;
3952         } else if (t < (2 / 2.75)) {
3953             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3954         } else if (t < (2.5 / 2.75)) {
3955             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3956         }
3957         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3958     },
3959
3960
3961     bounceBoth: function (t, b, c, d) {
3962         if (t < d / 2) {
3963             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3964         }
3965         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3966     }
3967 };/*
3968  * Portions of this file are based on pieces of Yahoo User Interface Library
3969  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3970  * YUI licensed under the BSD License:
3971  * http://developer.yahoo.net/yui/license.txt
3972  * <script type="text/javascript">
3973  *
3974  */
3975     (function() {
3976         Roo.lib.Motion = function(el, attributes, duration, method) {
3977             if (el) {
3978                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3979             }
3980         };
3981
3982         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3983
3984
3985         var Y = Roo.lib;
3986         var superclass = Y.Motion.superclass;
3987         var proto = Y.Motion.prototype;
3988
3989         proto.toString = function() {
3990             var el = this.getEl();
3991             var id = el.id || el.tagName;
3992             return ("Motion " + id);
3993         };
3994
3995         proto.patterns.points = /^points$/i;
3996
3997         proto.setAttribute = function(attr, val, unit) {
3998             if (this.patterns.points.test(attr)) {
3999                 unit = unit || 'px';
4000                 superclass.setAttribute.call(this, 'left', val[0], unit);
4001                 superclass.setAttribute.call(this, 'top', val[1], unit);
4002             } else {
4003                 superclass.setAttribute.call(this, attr, val, unit);
4004             }
4005         };
4006
4007         proto.getAttribute = function(attr) {
4008             if (this.patterns.points.test(attr)) {
4009                 var val = [
4010                         superclass.getAttribute.call(this, 'left'),
4011                         superclass.getAttribute.call(this, 'top')
4012                         ];
4013             } else {
4014                 val = superclass.getAttribute.call(this, attr);
4015             }
4016
4017             return val;
4018         };
4019
4020         proto.doMethod = function(attr, start, end) {
4021             var val = null;
4022
4023             if (this.patterns.points.test(attr)) {
4024                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4025                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4026             } else {
4027                 val = superclass.doMethod.call(this, attr, start, end);
4028             }
4029             return val;
4030         };
4031
4032         proto.setRuntimeAttribute = function(attr) {
4033             if (this.patterns.points.test(attr)) {
4034                 var el = this.getEl();
4035                 var attributes = this.attributes;
4036                 var start;
4037                 var control = attributes['points']['control'] || [];
4038                 var end;
4039                 var i, len;
4040
4041                 if (control.length > 0 && !(control[0] instanceof Array)) {
4042                     control = [control];
4043                 } else {
4044                     var tmp = [];
4045                     for (i = 0,len = control.length; i < len; ++i) {
4046                         tmp[i] = control[i];
4047                     }
4048                     control = tmp;
4049                 }
4050
4051                 Roo.fly(el).position();
4052
4053                 if (isset(attributes['points']['from'])) {
4054                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4055                 }
4056                 else {
4057                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4058                 }
4059
4060                 start = this.getAttribute('points');
4061
4062
4063                 if (isset(attributes['points']['to'])) {
4064                     end = translateValues.call(this, attributes['points']['to'], start);
4065
4066                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4067                     for (i = 0,len = control.length; i < len; ++i) {
4068                         control[i] = translateValues.call(this, control[i], start);
4069                     }
4070
4071
4072                 } else if (isset(attributes['points']['by'])) {
4073                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4074
4075                     for (i = 0,len = control.length; i < len; ++i) {
4076                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4077                     }
4078                 }
4079
4080                 this.runtimeAttributes[attr] = [start];
4081
4082                 if (control.length > 0) {
4083                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4084                 }
4085
4086                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4087             }
4088             else {
4089                 superclass.setRuntimeAttribute.call(this, attr);
4090             }
4091         };
4092
4093         var translateValues = function(val, start) {
4094             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4095             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4096
4097             return val;
4098         };
4099
4100         var isset = function(prop) {
4101             return (typeof prop !== 'undefined');
4102         };
4103     })();
4104 /*
4105  * Portions of this file are based on pieces of Yahoo User Interface Library
4106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4107  * YUI licensed under the BSD License:
4108  * http://developer.yahoo.net/yui/license.txt
4109  * <script type="text/javascript">
4110  *
4111  */
4112     (function() {
4113         Roo.lib.Scroll = function(el, attributes, duration, method) {
4114             if (el) {
4115                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4116             }
4117         };
4118
4119         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4120
4121
4122         var Y = Roo.lib;
4123         var superclass = Y.Scroll.superclass;
4124         var proto = Y.Scroll.prototype;
4125
4126         proto.toString = function() {
4127             var el = this.getEl();
4128             var id = el.id || el.tagName;
4129             return ("Scroll " + id);
4130         };
4131
4132         proto.doMethod = function(attr, start, end) {
4133             var val = null;
4134
4135             if (attr == 'scroll') {
4136                 val = [
4137                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4138                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4139                         ];
4140
4141             } else {
4142                 val = superclass.doMethod.call(this, attr, start, end);
4143             }
4144             return val;
4145         };
4146
4147         proto.getAttribute = function(attr) {
4148             var val = null;
4149             var el = this.getEl();
4150
4151             if (attr == 'scroll') {
4152                 val = [ el.scrollLeft, el.scrollTop ];
4153             } else {
4154                 val = superclass.getAttribute.call(this, attr);
4155             }
4156
4157             return val;
4158         };
4159
4160         proto.setAttribute = function(attr, val, unit) {
4161             var el = this.getEl();
4162
4163             if (attr == 'scroll') {
4164                 el.scrollLeft = val[0];
4165                 el.scrollTop = val[1];
4166             } else {
4167                 superclass.setAttribute.call(this, attr, val, unit);
4168             }
4169         };
4170     })();
4171 /*
4172  * Based on:
4173  * Ext JS Library 1.1.1
4174  * Copyright(c) 2006-2007, Ext JS, LLC.
4175  *
4176  * Originally Released Under LGPL - original licence link has changed is not relivant.
4177  *
4178  * Fork - LGPL
4179  * <script type="text/javascript">
4180  */
4181
4182
4183 // nasty IE9 hack - what a pile of crap that is..
4184
4185  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4186     Range.prototype.createContextualFragment = function (html) {
4187         var doc = window.document;
4188         var container = doc.createElement("div");
4189         container.innerHTML = html;
4190         var frag = doc.createDocumentFragment(), n;
4191         while ((n = container.firstChild)) {
4192             frag.appendChild(n);
4193         }
4194         return frag;
4195     };
4196 }
4197
4198 /**
4199  * @class Roo.DomHelper
4200  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4201  * 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>.
4202  * @singleton
4203  */
4204 Roo.DomHelper = function(){
4205     var tempTableEl = null;
4206     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4207     var tableRe = /^table|tbody|tr|td$/i;
4208     var xmlns = {};
4209     // build as innerHTML where available
4210     /** @ignore */
4211     var createHtml = function(o){
4212         if(typeof o == 'string'){
4213             return o;
4214         }
4215         var b = "";
4216         if(!o.tag){
4217             o.tag = "div";
4218         }
4219         b += "<" + o.tag;
4220         for(var attr in o){
4221             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4222             if(attr == "style"){
4223                 var s = o["style"];
4224                 if(typeof s == "function"){
4225                     s = s.call();
4226                 }
4227                 if(typeof s == "string"){
4228                     b += ' style="' + s + '"';
4229                 }else if(typeof s == "object"){
4230                     b += ' style="';
4231                     for(var key in s){
4232                         if(typeof s[key] != "function"){
4233                             b += key + ":" + s[key] + ";";
4234                         }
4235                     }
4236                     b += '"';
4237                 }
4238             }else{
4239                 if(attr == "cls"){
4240                     b += ' class="' + o["cls"] + '"';
4241                 }else if(attr == "htmlFor"){
4242                     b += ' for="' + o["htmlFor"] + '"';
4243                 }else{
4244                     b += " " + attr + '="' + o[attr] + '"';
4245                 }
4246             }
4247         }
4248         if(emptyTags.test(o.tag)){
4249             b += "/>";
4250         }else{
4251             b += ">";
4252             var cn = o.children || o.cn;
4253             if(cn){
4254                 //http://bugs.kde.org/show_bug.cgi?id=71506
4255                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4256                     for(var i = 0, len = cn.length; i < len; i++) {
4257                         b += createHtml(cn[i], b);
4258                     }
4259                 }else{
4260                     b += createHtml(cn, b);
4261                 }
4262             }
4263             if(o.html){
4264                 b += o.html;
4265             }
4266             b += "</" + o.tag + ">";
4267         }
4268         return b;
4269     };
4270
4271     // build as dom
4272     /** @ignore */
4273     var createDom = function(o, parentNode){
4274          
4275         // defininition craeted..
4276         var ns = false;
4277         if (o.ns && o.ns != 'html') {
4278                
4279             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4280                 xmlns[o.ns] = o.xmlns;
4281                 ns = o.xmlns;
4282             }
4283             if (typeof(xmlns[o.ns]) == 'undefined') {
4284                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4285             }
4286             ns = xmlns[o.ns];
4287         }
4288         
4289         
4290         if (typeof(o) == 'string') {
4291             return parentNode.appendChild(document.createTextNode(o));
4292         }
4293         o.tag = o.tag || div;
4294         if (o.ns && Roo.isIE) {
4295             ns = false;
4296             o.tag = o.ns + ':' + o.tag;
4297             
4298         }
4299         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4300         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4301         for(var attr in o){
4302             
4303             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4304                     attr == "style" || typeof o[attr] == "function") { continue; }
4305                     
4306             if(attr=="cls" && Roo.isIE){
4307                 el.className = o["cls"];
4308             }else{
4309                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4310                 else { 
4311                     el[attr] = o[attr];
4312                 }
4313             }
4314         }
4315         Roo.DomHelper.applyStyles(el, o.style);
4316         var cn = o.children || o.cn;
4317         if(cn){
4318             //http://bugs.kde.org/show_bug.cgi?id=71506
4319              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4320                 for(var i = 0, len = cn.length; i < len; i++) {
4321                     createDom(cn[i], el);
4322                 }
4323             }else{
4324                 createDom(cn, el);
4325             }
4326         }
4327         if(o.html){
4328             el.innerHTML = o.html;
4329         }
4330         if(parentNode){
4331            parentNode.appendChild(el);
4332         }
4333         return el;
4334     };
4335
4336     var ieTable = function(depth, s, h, e){
4337         tempTableEl.innerHTML = [s, h, e].join('');
4338         var i = -1, el = tempTableEl;
4339         while(++i < depth){
4340             el = el.firstChild;
4341         }
4342         return el;
4343     };
4344
4345     // kill repeat to save bytes
4346     var ts = '<table>',
4347         te = '</table>',
4348         tbs = ts+'<tbody>',
4349         tbe = '</tbody>'+te,
4350         trs = tbs + '<tr>',
4351         tre = '</tr>'+tbe;
4352
4353     /**
4354      * @ignore
4355      * Nasty code for IE's broken table implementation
4356      */
4357     var insertIntoTable = function(tag, where, el, html){
4358         if(!tempTableEl){
4359             tempTableEl = document.createElement('div');
4360         }
4361         var node;
4362         var before = null;
4363         if(tag == 'td'){
4364             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4365                 return;
4366             }
4367             if(where == 'beforebegin'){
4368                 before = el;
4369                 el = el.parentNode;
4370             } else{
4371                 before = el.nextSibling;
4372                 el = el.parentNode;
4373             }
4374             node = ieTable(4, trs, html, tre);
4375         }
4376         else if(tag == 'tr'){
4377             if(where == 'beforebegin'){
4378                 before = el;
4379                 el = el.parentNode;
4380                 node = ieTable(3, tbs, html, tbe);
4381             } else if(where == 'afterend'){
4382                 before = el.nextSibling;
4383                 el = el.parentNode;
4384                 node = ieTable(3, tbs, html, tbe);
4385             } else{ // INTO a TR
4386                 if(where == 'afterbegin'){
4387                     before = el.firstChild;
4388                 }
4389                 node = ieTable(4, trs, html, tre);
4390             }
4391         } else if(tag == 'tbody'){
4392             if(where == 'beforebegin'){
4393                 before = el;
4394                 el = el.parentNode;
4395                 node = ieTable(2, ts, html, te);
4396             } else if(where == 'afterend'){
4397                 before = el.nextSibling;
4398                 el = el.parentNode;
4399                 node = ieTable(2, ts, html, te);
4400             } else{
4401                 if(where == 'afterbegin'){
4402                     before = el.firstChild;
4403                 }
4404                 node = ieTable(3, tbs, html, tbe);
4405             }
4406         } else{ // TABLE
4407             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4408                 return;
4409             }
4410             if(where == 'afterbegin'){
4411                 before = el.firstChild;
4412             }
4413             node = ieTable(2, ts, html, te);
4414         }
4415         el.insertBefore(node, before);
4416         return node;
4417     };
4418
4419     return {
4420     /** True to force the use of DOM instead of html fragments @type Boolean */
4421     useDom : false,
4422
4423     /**
4424      * Returns the markup for the passed Element(s) config
4425      * @param {Object} o The Dom object spec (and children)
4426      * @return {String}
4427      */
4428     markup : function(o){
4429         return createHtml(o);
4430     },
4431
4432     /**
4433      * Applies a style specification to an element
4434      * @param {String/HTMLElement} el The element to apply styles to
4435      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4436      * a function which returns such a specification.
4437      */
4438     applyStyles : function(el, styles){
4439         if(styles){
4440            el = Roo.fly(el);
4441            if(typeof styles == "string"){
4442                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4443                var matches;
4444                while ((matches = re.exec(styles)) != null){
4445                    el.setStyle(matches[1], matches[2]);
4446                }
4447            }else if (typeof styles == "object"){
4448                for (var style in styles){
4449                   el.setStyle(style, styles[style]);
4450                }
4451            }else if (typeof styles == "function"){
4452                 Roo.DomHelper.applyStyles(el, styles.call());
4453            }
4454         }
4455     },
4456
4457     /**
4458      * Inserts an HTML fragment into the Dom
4459      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4460      * @param {HTMLElement} el The context element
4461      * @param {String} html The HTML fragmenet
4462      * @return {HTMLElement} The new node
4463      */
4464     insertHtml : function(where, el, html){
4465         where = where.toLowerCase();
4466         if(el.insertAdjacentHTML){
4467             if(tableRe.test(el.tagName)){
4468                 var rs;
4469                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4470                     return rs;
4471                 }
4472             }
4473             switch(where){
4474                 case "beforebegin":
4475                     el.insertAdjacentHTML('BeforeBegin', html);
4476                     return el.previousSibling;
4477                 case "afterbegin":
4478                     el.insertAdjacentHTML('AfterBegin', html);
4479                     return el.firstChild;
4480                 case "beforeend":
4481                     el.insertAdjacentHTML('BeforeEnd', html);
4482                     return el.lastChild;
4483                 case "afterend":
4484                     el.insertAdjacentHTML('AfterEnd', html);
4485                     return el.nextSibling;
4486             }
4487             throw 'Illegal insertion point -> "' + where + '"';
4488         }
4489         var range = el.ownerDocument.createRange();
4490         var frag;
4491         switch(where){
4492              case "beforebegin":
4493                 range.setStartBefore(el);
4494                 frag = range.createContextualFragment(html);
4495                 el.parentNode.insertBefore(frag, el);
4496                 return el.previousSibling;
4497              case "afterbegin":
4498                 if(el.firstChild){
4499                     range.setStartBefore(el.firstChild);
4500                     frag = range.createContextualFragment(html);
4501                     el.insertBefore(frag, el.firstChild);
4502                     return el.firstChild;
4503                 }else{
4504                     el.innerHTML = html;
4505                     return el.firstChild;
4506                 }
4507             case "beforeend":
4508                 if(el.lastChild){
4509                     range.setStartAfter(el.lastChild);
4510                     frag = range.createContextualFragment(html);
4511                     el.appendChild(frag);
4512                     return el.lastChild;
4513                 }else{
4514                     el.innerHTML = html;
4515                     return el.lastChild;
4516                 }
4517             case "afterend":
4518                 range.setStartAfter(el);
4519                 frag = range.createContextualFragment(html);
4520                 el.parentNode.insertBefore(frag, el.nextSibling);
4521                 return el.nextSibling;
4522             }
4523             throw 'Illegal insertion point -> "' + where + '"';
4524     },
4525
4526     /**
4527      * Creates new Dom element(s) and inserts them before el
4528      * @param {String/HTMLElement/Element} el The context element
4529      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531      * @return {HTMLElement/Roo.Element} The new node
4532      */
4533     insertBefore : function(el, o, returnElement){
4534         return this.doInsert(el, o, returnElement, "beforeBegin");
4535     },
4536
4537     /**
4538      * Creates new Dom element(s) and inserts them after el
4539      * @param {String/HTMLElement/Element} el The context element
4540      * @param {Object} o The Dom object spec (and children)
4541      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542      * @return {HTMLElement/Roo.Element} The new node
4543      */
4544     insertAfter : function(el, o, returnElement){
4545         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4546     },
4547
4548     /**
4549      * Creates new Dom element(s) and inserts them as the first child of el
4550      * @param {String/HTMLElement/Element} el The context element
4551      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4552      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553      * @return {HTMLElement/Roo.Element} The new node
4554      */
4555     insertFirst : function(el, o, returnElement){
4556         return this.doInsert(el, o, returnElement, "afterBegin");
4557     },
4558
4559     // private
4560     doInsert : function(el, o, returnElement, pos, sibling){
4561         el = Roo.getDom(el);
4562         var newNode;
4563         if(this.useDom || o.ns){
4564             newNode = createDom(o, null);
4565             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4566         }else{
4567             var html = createHtml(o);
4568             newNode = this.insertHtml(pos, el, html);
4569         }
4570         return returnElement ? Roo.get(newNode, true) : newNode;
4571     },
4572
4573     /**
4574      * Creates new Dom element(s) and appends them to el
4575      * @param {String/HTMLElement/Element} el The context element
4576      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4577      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4578      * @return {HTMLElement/Roo.Element} The new node
4579      */
4580     append : function(el, o, returnElement){
4581         el = Roo.getDom(el);
4582         var newNode;
4583         if(this.useDom || o.ns){
4584             newNode = createDom(o, null);
4585             el.appendChild(newNode);
4586         }else{
4587             var html = createHtml(o);
4588             newNode = this.insertHtml("beforeEnd", el, html);
4589         }
4590         return returnElement ? Roo.get(newNode, true) : newNode;
4591     },
4592
4593     /**
4594      * Creates new Dom element(s) and overwrites the contents of el with them
4595      * @param {String/HTMLElement/Element} el The context element
4596      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4597      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4598      * @return {HTMLElement/Roo.Element} The new node
4599      */
4600     overwrite : function(el, o, returnElement){
4601         el = Roo.getDom(el);
4602         if (o.ns) {
4603           
4604             while (el.childNodes.length) {
4605                 el.removeChild(el.firstChild);
4606             }
4607             createDom(o, el);
4608         } else {
4609             el.innerHTML = createHtml(o);   
4610         }
4611         
4612         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4613     },
4614
4615     /**
4616      * Creates a new Roo.DomHelper.Template from the Dom object spec
4617      * @param {Object} o The Dom object spec (and children)
4618      * @return {Roo.DomHelper.Template} The new template
4619      */
4620     createTemplate : function(o){
4621         var html = createHtml(o);
4622         return new Roo.Template(html);
4623     }
4624     };
4625 }();
4626 /*
4627  * Based on:
4628  * Ext JS Library 1.1.1
4629  * Copyright(c) 2006-2007, Ext JS, LLC.
4630  *
4631  * Originally Released Under LGPL - original licence link has changed is not relivant.
4632  *
4633  * Fork - LGPL
4634  * <script type="text/javascript">
4635  */
4636  
4637 /**
4638 * @class Roo.Template
4639 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4640 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4641 * Usage:
4642 <pre><code>
4643 var t = new Roo.Template({
4644     html :  '&lt;div name="{id}"&gt;' + 
4645         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4646         '&lt;/div&gt;',
4647     myformat: function (value, allValues) {
4648         return 'XX' + value;
4649     }
4650 });
4651 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4652 </code></pre>
4653 * For more information see this blog post with examples:
4654 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4655      - Create Elements using DOM, HTML fragments and Templates</a>. 
4656 * @constructor
4657 * @param {Object} cfg - Configuration object.
4658 */
4659 Roo.Template = function(cfg){
4660     // BC!
4661     if(cfg instanceof Array){
4662         cfg = cfg.join("");
4663     }else if(arguments.length > 1){
4664         cfg = Array.prototype.join.call(arguments, "");
4665     }
4666     
4667     
4668     if (typeof(cfg) == 'object') {
4669         Roo.apply(this,cfg)
4670     } else {
4671         // bc
4672         this.html = cfg;
4673     }
4674     if (this.url) {
4675         this.load();
4676     }
4677     
4678 };
4679 Roo.Template.prototype = {
4680     
4681     /**
4682      * @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..
4683      *                    it should be fixed so that template is observable...
4684      */
4685     url : false,
4686     /**
4687      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4688      */
4689     html : '',
4690     /**
4691      * Returns an HTML fragment of this template with the specified values applied.
4692      * @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'})
4693      * @return {String} The HTML fragment
4694      */
4695     applyTemplate : function(values){
4696         //Roo.log(["applyTemplate", values]);
4697         try {
4698            
4699             if(this.compiled){
4700                 return this.compiled(values);
4701             }
4702             var useF = this.disableFormats !== true;
4703             var fm = Roo.util.Format, tpl = this;
4704             var fn = function(m, name, format, args){
4705                 if(format && useF){
4706                     if(format.substr(0, 5) == "this."){
4707                         return tpl.call(format.substr(5), values[name], values);
4708                     }else{
4709                         if(args){
4710                             // quoted values are required for strings in compiled templates, 
4711                             // but for non compiled we need to strip them
4712                             // quoted reversed for jsmin
4713                             var re = /^\s*['"](.*)["']\s*$/;
4714                             args = args.split(',');
4715                             for(var i = 0, len = args.length; i < len; i++){
4716                                 args[i] = args[i].replace(re, "$1");
4717                             }
4718                             args = [values[name]].concat(args);
4719                         }else{
4720                             args = [values[name]];
4721                         }
4722                         return fm[format].apply(fm, args);
4723                     }
4724                 }else{
4725                     return values[name] !== undefined ? values[name] : "";
4726                 }
4727             };
4728             return this.html.replace(this.re, fn);
4729         } catch (e) {
4730             Roo.log(e);
4731             throw e;
4732         }
4733          
4734     },
4735     
4736     loading : false,
4737       
4738     load : function ()
4739     {
4740          
4741         if (this.loading) {
4742             return;
4743         }
4744         var _t = this;
4745         
4746         this.loading = true;
4747         this.compiled = false;
4748         
4749         var cx = new Roo.data.Connection();
4750         cx.request({
4751             url : this.url,
4752             method : 'GET',
4753             success : function (response) {
4754                 _t.loading = false;
4755                 _t.html = response.responseText;
4756                 _t.url = false;
4757                 _t.compile();
4758              },
4759             failure : function(response) {
4760                 Roo.log("Template failed to load from " + _t.url);
4761                 _t.loading = false;
4762             }
4763         });
4764     },
4765
4766     /**
4767      * Sets the HTML used as the template and optionally compiles it.
4768      * @param {String} html
4769      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4770      * @return {Roo.Template} this
4771      */
4772     set : function(html, compile){
4773         this.html = html;
4774         this.compiled = null;
4775         if(compile){
4776             this.compile();
4777         }
4778         return this;
4779     },
4780     
4781     /**
4782      * True to disable format functions (defaults to false)
4783      * @type Boolean
4784      */
4785     disableFormats : false,
4786     
4787     /**
4788     * The regular expression used to match template variables 
4789     * @type RegExp
4790     * @property 
4791     */
4792     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4793     
4794     /**
4795      * Compiles the template into an internal function, eliminating the RegEx overhead.
4796      * @return {Roo.Template} this
4797      */
4798     compile : function(){
4799         var fm = Roo.util.Format;
4800         var useF = this.disableFormats !== true;
4801         var sep = Roo.isGecko ? "+" : ",";
4802         var fn = function(m, name, format, args){
4803             if(format && useF){
4804                 args = args ? ',' + args : "";
4805                 if(format.substr(0, 5) != "this."){
4806                     format = "fm." + format + '(';
4807                 }else{
4808                     format = 'this.call("'+ format.substr(5) + '", ';
4809                     args = ", values";
4810                 }
4811             }else{
4812                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4813             }
4814             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4815         };
4816         var body;
4817         // branched to use + in gecko and [].join() in others
4818         if(Roo.isGecko){
4819             body = "this.compiled = function(values){ return '" +
4820                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4821                     "';};";
4822         }else{
4823             body = ["this.compiled = function(values){ return ['"];
4824             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4825             body.push("'].join('');};");
4826             body = body.join('');
4827         }
4828         /**
4829          * eval:var:values
4830          * eval:var:fm
4831          */
4832         eval(body);
4833         return this;
4834     },
4835     
4836     // private function used to call members
4837     call : function(fnName, value, allValues){
4838         return this[fnName](value, allValues);
4839     },
4840     
4841     /**
4842      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4843      * @param {String/HTMLElement/Roo.Element} el The context element
4844      * @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'})
4845      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4846      * @return {HTMLElement/Roo.Element} The new node or Element
4847      */
4848     insertFirst: function(el, values, returnElement){
4849         return this.doInsert('afterBegin', el, values, returnElement);
4850     },
4851
4852     /**
4853      * Applies the supplied values to the template and inserts the new node(s) before el.
4854      * @param {String/HTMLElement/Roo.Element} el The context element
4855      * @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'})
4856      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4857      * @return {HTMLElement/Roo.Element} The new node or Element
4858      */
4859     insertBefore: function(el, values, returnElement){
4860         return this.doInsert('beforeBegin', el, values, returnElement);
4861     },
4862
4863     /**
4864      * Applies the supplied values to the template and inserts the new node(s) after el.
4865      * @param {String/HTMLElement/Roo.Element} el The context element
4866      * @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'})
4867      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4868      * @return {HTMLElement/Roo.Element} The new node or Element
4869      */
4870     insertAfter : function(el, values, returnElement){
4871         return this.doInsert('afterEnd', el, values, returnElement);
4872     },
4873     
4874     /**
4875      * Applies the supplied values to the template and appends the new node(s) to el.
4876      * @param {String/HTMLElement/Roo.Element} el The context element
4877      * @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'})
4878      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4879      * @return {HTMLElement/Roo.Element} The new node or Element
4880      */
4881     append : function(el, values, returnElement){
4882         return this.doInsert('beforeEnd', el, values, returnElement);
4883     },
4884
4885     doInsert : function(where, el, values, returnEl){
4886         el = Roo.getDom(el);
4887         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4888         return returnEl ? Roo.get(newNode, true) : newNode;
4889     },
4890
4891     /**
4892      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4893      * @param {String/HTMLElement/Roo.Element} el The context element
4894      * @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'})
4895      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896      * @return {HTMLElement/Roo.Element} The new node or Element
4897      */
4898     overwrite : function(el, values, returnElement){
4899         el = Roo.getDom(el);
4900         el.innerHTML = this.applyTemplate(values);
4901         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4902     }
4903 };
4904 /**
4905  * Alias for {@link #applyTemplate}
4906  * @method
4907  */
4908 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4909
4910 // backwards compat
4911 Roo.DomHelper.Template = Roo.Template;
4912
4913 /**
4914  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4915  * @param {String/HTMLElement} el A DOM element or its id
4916  * @returns {Roo.Template} The created template
4917  * @static
4918  */
4919 Roo.Template.from = function(el){
4920     el = Roo.getDom(el);
4921     return new Roo.Template(el.value || el.innerHTML);
4922 };/*
4923  * Based on:
4924  * Ext JS Library 1.1.1
4925  * Copyright(c) 2006-2007, Ext JS, LLC.
4926  *
4927  * Originally Released Under LGPL - original licence link has changed is not relivant.
4928  *
4929  * Fork - LGPL
4930  * <script type="text/javascript">
4931  */
4932  
4933
4934 /*
4935  * This is code is also distributed under MIT license for use
4936  * with jQuery and prototype JavaScript libraries.
4937  */
4938 /**
4939  * @class Roo.DomQuery
4940 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).
4941 <p>
4942 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>
4943
4944 <p>
4945 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.
4946 </p>
4947 <h4>Element Selectors:</h4>
4948 <ul class="list">
4949     <li> <b>*</b> any element</li>
4950     <li> <b>E</b> an element with the tag E</li>
4951     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4952     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4953     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4954     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4955 </ul>
4956 <h4>Attribute Selectors:</h4>
4957 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4958 <ul class="list">
4959     <li> <b>E[foo]</b> has an attribute "foo"</li>
4960     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4961     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4962     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4963     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4964     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4965     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4966 </ul>
4967 <h4>Pseudo Classes:</h4>
4968 <ul class="list">
4969     <li> <b>E:first-child</b> E is the first child of its parent</li>
4970     <li> <b>E:last-child</b> E is the last child of its parent</li>
4971     <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>
4972     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4973     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4974     <li> <b>E:only-child</b> E is the only child of its parent</li>
4975     <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>
4976     <li> <b>E:first</b> the first E in the resultset</li>
4977     <li> <b>E:last</b> the last E in the resultset</li>
4978     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4979     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4980     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4981     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4982     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4983     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4984     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4985     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4986     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4987 </ul>
4988 <h4>CSS Value Selectors:</h4>
4989 <ul class="list">
4990     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4991     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4992     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4993     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4994     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4995     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4996 </ul>
4997  * @singleton
4998  */
4999 Roo.DomQuery = function(){
5000     var cache = {}, simpleCache = {}, valueCache = {};
5001     var nonSpace = /\S/;
5002     var trimRe = /^\s+|\s+$/g;
5003     var tplRe = /\{(\d+)\}/g;
5004     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5005     var tagTokenRe = /^(#)?([\w-\*]+)/;
5006     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5007
5008     function child(p, index){
5009         var i = 0;
5010         var n = p.firstChild;
5011         while(n){
5012             if(n.nodeType == 1){
5013                if(++i == index){
5014                    return n;
5015                }
5016             }
5017             n = n.nextSibling;
5018         }
5019         return null;
5020     };
5021
5022     function next(n){
5023         while((n = n.nextSibling) && n.nodeType != 1);
5024         return n;
5025     };
5026
5027     function prev(n){
5028         while((n = n.previousSibling) && n.nodeType != 1);
5029         return n;
5030     };
5031
5032     function children(d){
5033         var n = d.firstChild, ni = -1;
5034             while(n){
5035                 var nx = n.nextSibling;
5036                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5037                     d.removeChild(n);
5038                 }else{
5039                     n.nodeIndex = ++ni;
5040                 }
5041                 n = nx;
5042             }
5043             return this;
5044         };
5045
5046     function byClassName(c, a, v){
5047         if(!v){
5048             return c;
5049         }
5050         var r = [], ri = -1, cn;
5051         for(var i = 0, ci; ci = c[i]; i++){
5052             if((' '+ci.className+' ').indexOf(v) != -1){
5053                 r[++ri] = ci;
5054             }
5055         }
5056         return r;
5057     };
5058
5059     function attrValue(n, attr){
5060         if(!n.tagName && typeof n.length != "undefined"){
5061             n = n[0];
5062         }
5063         if(!n){
5064             return null;
5065         }
5066         if(attr == "for"){
5067             return n.htmlFor;
5068         }
5069         if(attr == "class" || attr == "className"){
5070             return n.className;
5071         }
5072         return n.getAttribute(attr) || n[attr];
5073
5074     };
5075
5076     function getNodes(ns, mode, tagName){
5077         var result = [], ri = -1, cs;
5078         if(!ns){
5079             return result;
5080         }
5081         tagName = tagName || "*";
5082         if(typeof ns.getElementsByTagName != "undefined"){
5083             ns = [ns];
5084         }
5085         if(!mode){
5086             for(var i = 0, ni; ni = ns[i]; i++){
5087                 cs = ni.getElementsByTagName(tagName);
5088                 for(var j = 0, ci; ci = cs[j]; j++){
5089                     result[++ri] = ci;
5090                 }
5091             }
5092         }else if(mode == "/" || mode == ">"){
5093             var utag = tagName.toUpperCase();
5094             for(var i = 0, ni, cn; ni = ns[i]; i++){
5095                 cn = ni.children || ni.childNodes;
5096                 for(var j = 0, cj; cj = cn[j]; j++){
5097                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5098                         result[++ri] = cj;
5099                     }
5100                 }
5101             }
5102         }else if(mode == "+"){
5103             var utag = tagName.toUpperCase();
5104             for(var i = 0, n; n = ns[i]; i++){
5105                 while((n = n.nextSibling) && n.nodeType != 1);
5106                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5107                     result[++ri] = n;
5108                 }
5109             }
5110         }else if(mode == "~"){
5111             for(var i = 0, n; n = ns[i]; i++){
5112                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5113                 if(n){
5114                     result[++ri] = n;
5115                 }
5116             }
5117         }
5118         return result;
5119     };
5120
5121     function concat(a, b){
5122         if(b.slice){
5123             return a.concat(b);
5124         }
5125         for(var i = 0, l = b.length; i < l; i++){
5126             a[a.length] = b[i];
5127         }
5128         return a;
5129     }
5130
5131     function byTag(cs, tagName){
5132         if(cs.tagName || cs == document){
5133             cs = [cs];
5134         }
5135         if(!tagName){
5136             return cs;
5137         }
5138         var r = [], ri = -1;
5139         tagName = tagName.toLowerCase();
5140         for(var i = 0, ci; ci = cs[i]; i++){
5141             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5142                 r[++ri] = ci;
5143             }
5144         }
5145         return r;
5146     };
5147
5148     function byId(cs, attr, id){
5149         if(cs.tagName || cs == document){
5150             cs = [cs];
5151         }
5152         if(!id){
5153             return cs;
5154         }
5155         var r = [], ri = -1;
5156         for(var i = 0,ci; ci = cs[i]; i++){
5157             if(ci && ci.id == id){
5158                 r[++ri] = ci;
5159                 return r;
5160             }
5161         }
5162         return r;
5163     };
5164
5165     function byAttribute(cs, attr, value, op, custom){
5166         var r = [], ri = -1, st = custom=="{";
5167         var f = Roo.DomQuery.operators[op];
5168         for(var i = 0, ci; ci = cs[i]; i++){
5169             var a;
5170             if(st){
5171                 a = Roo.DomQuery.getStyle(ci, attr);
5172             }
5173             else if(attr == "class" || attr == "className"){
5174                 a = ci.className;
5175             }else if(attr == "for"){
5176                 a = ci.htmlFor;
5177             }else if(attr == "href"){
5178                 a = ci.getAttribute("href", 2);
5179             }else{
5180                 a = ci.getAttribute(attr);
5181             }
5182             if((f && f(a, value)) || (!f && a)){
5183                 r[++ri] = ci;
5184             }
5185         }
5186         return r;
5187     };
5188
5189     function byPseudo(cs, name, value){
5190         return Roo.DomQuery.pseudos[name](cs, value);
5191     };
5192
5193     // This is for IE MSXML which does not support expandos.
5194     // IE runs the same speed using setAttribute, however FF slows way down
5195     // and Safari completely fails so they need to continue to use expandos.
5196     var isIE = window.ActiveXObject ? true : false;
5197
5198     // this eval is stop the compressor from
5199     // renaming the variable to something shorter
5200     
5201     /** eval:var:batch */
5202     var batch = 30803; 
5203
5204     var key = 30803;
5205
5206     function nodupIEXml(cs){
5207         var d = ++key;
5208         cs[0].setAttribute("_nodup", d);
5209         var r = [cs[0]];
5210         for(var i = 1, len = cs.length; i < len; i++){
5211             var c = cs[i];
5212             if(!c.getAttribute("_nodup") != d){
5213                 c.setAttribute("_nodup", d);
5214                 r[r.length] = c;
5215             }
5216         }
5217         for(var i = 0, len = cs.length; i < len; i++){
5218             cs[i].removeAttribute("_nodup");
5219         }
5220         return r;
5221     }
5222
5223     function nodup(cs){
5224         if(!cs){
5225             return [];
5226         }
5227         var len = cs.length, c, i, r = cs, cj, ri = -1;
5228         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5229             return cs;
5230         }
5231         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5232             return nodupIEXml(cs);
5233         }
5234         var d = ++key;
5235         cs[0]._nodup = d;
5236         for(i = 1; c = cs[i]; i++){
5237             if(c._nodup != d){
5238                 c._nodup = d;
5239             }else{
5240                 r = [];
5241                 for(var j = 0; j < i; j++){
5242                     r[++ri] = cs[j];
5243                 }
5244                 for(j = i+1; cj = cs[j]; j++){
5245                     if(cj._nodup != d){
5246                         cj._nodup = d;
5247                         r[++ri] = cj;
5248                     }
5249                 }
5250                 return r;
5251             }
5252         }
5253         return r;
5254     }
5255
5256     function quickDiffIEXml(c1, c2){
5257         var d = ++key;
5258         for(var i = 0, len = c1.length; i < len; i++){
5259             c1[i].setAttribute("_qdiff", d);
5260         }
5261         var r = [];
5262         for(var i = 0, len = c2.length; i < len; i++){
5263             if(c2[i].getAttribute("_qdiff") != d){
5264                 r[r.length] = c2[i];
5265             }
5266         }
5267         for(var i = 0, len = c1.length; i < len; i++){
5268            c1[i].removeAttribute("_qdiff");
5269         }
5270         return r;
5271     }
5272
5273     function quickDiff(c1, c2){
5274         var len1 = c1.length;
5275         if(!len1){
5276             return c2;
5277         }
5278         if(isIE && c1[0].selectSingleNode){
5279             return quickDiffIEXml(c1, c2);
5280         }
5281         var d = ++key;
5282         for(var i = 0; i < len1; i++){
5283             c1[i]._qdiff = d;
5284         }
5285         var r = [];
5286         for(var i = 0, len = c2.length; i < len; i++){
5287             if(c2[i]._qdiff != d){
5288                 r[r.length] = c2[i];
5289             }
5290         }
5291         return r;
5292     }
5293
5294     function quickId(ns, mode, root, id){
5295         if(ns == root){
5296            var d = root.ownerDocument || root;
5297            return d.getElementById(id);
5298         }
5299         ns = getNodes(ns, mode, "*");
5300         return byId(ns, null, id);
5301     }
5302
5303     return {
5304         getStyle : function(el, name){
5305             return Roo.fly(el).getStyle(name);
5306         },
5307         /**
5308          * Compiles a selector/xpath query into a reusable function. The returned function
5309          * takes one parameter "root" (optional), which is the context node from where the query should start.
5310          * @param {String} selector The selector/xpath query
5311          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5312          * @return {Function}
5313          */
5314         compile : function(path, type){
5315             type = type || "select";
5316             
5317             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5318             var q = path, mode, lq;
5319             var tk = Roo.DomQuery.matchers;
5320             var tklen = tk.length;
5321             var mm;
5322
5323             // accept leading mode switch
5324             var lmode = q.match(modeRe);
5325             if(lmode && lmode[1]){
5326                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5327                 q = q.replace(lmode[1], "");
5328             }
5329             // strip leading slashes
5330             while(path.substr(0, 1)=="/"){
5331                 path = path.substr(1);
5332             }
5333
5334             while(q && lq != q){
5335                 lq = q;
5336                 var tm = q.match(tagTokenRe);
5337                 if(type == "select"){
5338                     if(tm){
5339                         if(tm[1] == "#"){
5340                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5341                         }else{
5342                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5343                         }
5344                         q = q.replace(tm[0], "");
5345                     }else if(q.substr(0, 1) != '@'){
5346                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5347                     }
5348                 }else{
5349                     if(tm){
5350                         if(tm[1] == "#"){
5351                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5352                         }else{
5353                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5354                         }
5355                         q = q.replace(tm[0], "");
5356                     }
5357                 }
5358                 while(!(mm = q.match(modeRe))){
5359                     var matched = false;
5360                     for(var j = 0; j < tklen; j++){
5361                         var t = tk[j];
5362                         var m = q.match(t.re);
5363                         if(m){
5364                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5365                                                     return m[i];
5366                                                 });
5367                             q = q.replace(m[0], "");
5368                             matched = true;
5369                             break;
5370                         }
5371                     }
5372                     // prevent infinite loop on bad selector
5373                     if(!matched){
5374                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5375                     }
5376                 }
5377                 if(mm[1]){
5378                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5379                     q = q.replace(mm[1], "");
5380                 }
5381             }
5382             fn[fn.length] = "return nodup(n);\n}";
5383             
5384              /** 
5385               * list of variables that need from compression as they are used by eval.
5386              *  eval:var:batch 
5387              *  eval:var:nodup
5388              *  eval:var:byTag
5389              *  eval:var:ById
5390              *  eval:var:getNodes
5391              *  eval:var:quickId
5392              *  eval:var:mode
5393              *  eval:var:root
5394              *  eval:var:n
5395              *  eval:var:byClassName
5396              *  eval:var:byPseudo
5397              *  eval:var:byAttribute
5398              *  eval:var:attrValue
5399              * 
5400              **/ 
5401             eval(fn.join(""));
5402             return f;
5403         },
5404
5405         /**
5406          * Selects a group of elements.
5407          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5408          * @param {Node} root (optional) The start of the query (defaults to document).
5409          * @return {Array}
5410          */
5411         select : function(path, root, type){
5412             if(!root || root == document){
5413                 root = document;
5414             }
5415             if(typeof root == "string"){
5416                 root = document.getElementById(root);
5417             }
5418             var paths = path.split(",");
5419             var results = [];
5420             for(var i = 0, len = paths.length; i < len; i++){
5421                 var p = paths[i].replace(trimRe, "");
5422                 if(!cache[p]){
5423                     cache[p] = Roo.DomQuery.compile(p);
5424                     if(!cache[p]){
5425                         throw p + " is not a valid selector";
5426                     }
5427                 }
5428                 var result = cache[p](root);
5429                 if(result && result != document){
5430                     results = results.concat(result);
5431                 }
5432             }
5433             if(paths.length > 1){
5434                 return nodup(results);
5435             }
5436             return results;
5437         },
5438
5439         /**
5440          * Selects a single element.
5441          * @param {String} selector The selector/xpath query
5442          * @param {Node} root (optional) The start of the query (defaults to document).
5443          * @return {Element}
5444          */
5445         selectNode : function(path, root){
5446             return Roo.DomQuery.select(path, root)[0];
5447         },
5448
5449         /**
5450          * Selects the value of a node, optionally replacing null with the defaultValue.
5451          * @param {String} selector The selector/xpath query
5452          * @param {Node} root (optional) The start of the query (defaults to document).
5453          * @param {String} defaultValue
5454          */
5455         selectValue : function(path, root, defaultValue){
5456             path = path.replace(trimRe, "");
5457             if(!valueCache[path]){
5458                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5459             }
5460             var n = valueCache[path](root);
5461             n = n[0] ? n[0] : n;
5462             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5463             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5464         },
5465
5466         /**
5467          * Selects the value of a node, parsing integers and floats.
5468          * @param {String} selector The selector/xpath query
5469          * @param {Node} root (optional) The start of the query (defaults to document).
5470          * @param {Number} defaultValue
5471          * @return {Number}
5472          */
5473         selectNumber : function(path, root, defaultValue){
5474             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5475             return parseFloat(v);
5476         },
5477
5478         /**
5479          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5480          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5481          * @param {String} selector The simple selector to test
5482          * @return {Boolean}
5483          */
5484         is : function(el, ss){
5485             if(typeof el == "string"){
5486                 el = document.getElementById(el);
5487             }
5488             var isArray = (el instanceof Array);
5489             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5490             return isArray ? (result.length == el.length) : (result.length > 0);
5491         },
5492
5493         /**
5494          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5495          * @param {Array} el An array of elements to filter
5496          * @param {String} selector The simple selector to test
5497          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5498          * the selector instead of the ones that match
5499          * @return {Array}
5500          */
5501         filter : function(els, ss, nonMatches){
5502             ss = ss.replace(trimRe, "");
5503             if(!simpleCache[ss]){
5504                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5505             }
5506             var result = simpleCache[ss](els);
5507             return nonMatches ? quickDiff(result, els) : result;
5508         },
5509
5510         /**
5511          * Collection of matching regular expressions and code snippets.
5512          */
5513         matchers : [{
5514                 re: /^\.([\w-]+)/,
5515                 select: 'n = byClassName(n, null, " {1} ");'
5516             }, {
5517                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5518                 select: 'n = byPseudo(n, "{1}", "{2}");'
5519             },{
5520                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5521                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5522             }, {
5523                 re: /^#([\w-]+)/,
5524                 select: 'n = byId(n, null, "{1}");'
5525             },{
5526                 re: /^@([\w-]+)/,
5527                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5528             }
5529         ],
5530
5531         /**
5532          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5533          * 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;.
5534          */
5535         operators : {
5536             "=" : function(a, v){
5537                 return a == v;
5538             },
5539             "!=" : function(a, v){
5540                 return a != v;
5541             },
5542             "^=" : function(a, v){
5543                 return a && a.substr(0, v.length) == v;
5544             },
5545             "$=" : function(a, v){
5546                 return a && a.substr(a.length-v.length) == v;
5547             },
5548             "*=" : function(a, v){
5549                 return a && a.indexOf(v) !== -1;
5550             },
5551             "%=" : function(a, v){
5552                 return (a % v) == 0;
5553             },
5554             "|=" : function(a, v){
5555                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5556             },
5557             "~=" : function(a, v){
5558                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5559             }
5560         },
5561
5562         /**
5563          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5564          * and the argument (if any) supplied in the selector.
5565          */
5566         pseudos : {
5567             "first-child" : function(c){
5568                 var r = [], ri = -1, n;
5569                 for(var i = 0, ci; ci = n = c[i]; i++){
5570                     while((n = n.previousSibling) && n.nodeType != 1);
5571                     if(!n){
5572                         r[++ri] = ci;
5573                     }
5574                 }
5575                 return r;
5576             },
5577
5578             "last-child" : function(c){
5579                 var r = [], ri = -1, n;
5580                 for(var i = 0, ci; ci = n = c[i]; i++){
5581                     while((n = n.nextSibling) && n.nodeType != 1);
5582                     if(!n){
5583                         r[++ri] = ci;
5584                     }
5585                 }
5586                 return r;
5587             },
5588
5589             "nth-child" : function(c, a) {
5590                 var r = [], ri = -1;
5591                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5592                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5593                 for(var i = 0, n; n = c[i]; i++){
5594                     var pn = n.parentNode;
5595                     if (batch != pn._batch) {
5596                         var j = 0;
5597                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5598                             if(cn.nodeType == 1){
5599                                cn.nodeIndex = ++j;
5600                             }
5601                         }
5602                         pn._batch = batch;
5603                     }
5604                     if (f == 1) {
5605                         if (l == 0 || n.nodeIndex == l){
5606                             r[++ri] = n;
5607                         }
5608                     } else if ((n.nodeIndex + l) % f == 0){
5609                         r[++ri] = n;
5610                     }
5611                 }
5612
5613                 return r;
5614             },
5615
5616             "only-child" : function(c){
5617                 var r = [], ri = -1;;
5618                 for(var i = 0, ci; ci = c[i]; i++){
5619                     if(!prev(ci) && !next(ci)){
5620                         r[++ri] = ci;
5621                     }
5622                 }
5623                 return r;
5624             },
5625
5626             "empty" : function(c){
5627                 var r = [], ri = -1;
5628                 for(var i = 0, ci; ci = c[i]; i++){
5629                     var cns = ci.childNodes, j = 0, cn, empty = true;
5630                     while(cn = cns[j]){
5631                         ++j;
5632                         if(cn.nodeType == 1 || cn.nodeType == 3){
5633                             empty = false;
5634                             break;
5635                         }
5636                     }
5637                     if(empty){
5638                         r[++ri] = ci;
5639                     }
5640                 }
5641                 return r;
5642             },
5643
5644             "contains" : function(c, v){
5645                 var r = [], ri = -1;
5646                 for(var i = 0, ci; ci = c[i]; i++){
5647                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5648                         r[++ri] = ci;
5649                     }
5650                 }
5651                 return r;
5652             },
5653
5654             "nodeValue" : function(c, v){
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5658                         r[++ri] = ci;
5659                     }
5660                 }
5661                 return r;
5662             },
5663
5664             "checked" : function(c){
5665                 var r = [], ri = -1;
5666                 for(var i = 0, ci; ci = c[i]; i++){
5667                     if(ci.checked == true){
5668                         r[++ri] = ci;
5669                     }
5670                 }
5671                 return r;
5672             },
5673
5674             "not" : function(c, ss){
5675                 return Roo.DomQuery.filter(c, ss, true);
5676             },
5677
5678             "odd" : function(c){
5679                 return this["nth-child"](c, "odd");
5680             },
5681
5682             "even" : function(c){
5683                 return this["nth-child"](c, "even");
5684             },
5685
5686             "nth" : function(c, a){
5687                 return c[a-1] || [];
5688             },
5689
5690             "first" : function(c){
5691                 return c[0] || [];
5692             },
5693
5694             "last" : function(c){
5695                 return c[c.length-1] || [];
5696             },
5697
5698             "has" : function(c, ss){
5699                 var s = Roo.DomQuery.select;
5700                 var r = [], ri = -1;
5701                 for(var i = 0, ci; ci = c[i]; i++){
5702                     if(s(ss, ci).length > 0){
5703                         r[++ri] = ci;
5704                     }
5705                 }
5706                 return r;
5707             },
5708
5709             "next" : function(c, ss){
5710                 var is = Roo.DomQuery.is;
5711                 var r = [], ri = -1;
5712                 for(var i = 0, ci; ci = c[i]; i++){
5713                     var n = next(ci);
5714                     if(n && is(n, ss)){
5715                         r[++ri] = ci;
5716                     }
5717                 }
5718                 return r;
5719             },
5720
5721             "prev" : function(c, ss){
5722                 var is = Roo.DomQuery.is;
5723                 var r = [], ri = -1;
5724                 for(var i = 0, ci; ci = c[i]; i++){
5725                     var n = prev(ci);
5726                     if(n && is(n, ss)){
5727                         r[++ri] = ci;
5728                     }
5729                 }
5730                 return r;
5731             }
5732         }
5733     };
5734 }();
5735
5736 /**
5737  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5738  * @param {String} path The selector/xpath query
5739  * @param {Node} root (optional) The start of the query (defaults to document).
5740  * @return {Array}
5741  * @member Roo
5742  * @method query
5743  */
5744 Roo.query = Roo.DomQuery.select;
5745 /*
5746  * Based on:
5747  * Ext JS Library 1.1.1
5748  * Copyright(c) 2006-2007, Ext JS, LLC.
5749  *
5750  * Originally Released Under LGPL - original licence link has changed is not relivant.
5751  *
5752  * Fork - LGPL
5753  * <script type="text/javascript">
5754  */
5755
5756 /**
5757  * @class Roo.util.Observable
5758  * Base class that provides a common interface for publishing events. Subclasses are expected to
5759  * to have a property "events" with all the events defined.<br>
5760  * For example:
5761  * <pre><code>
5762  Employee = function(name){
5763     this.name = name;
5764     this.addEvents({
5765         "fired" : true,
5766         "quit" : true
5767     });
5768  }
5769  Roo.extend(Employee, Roo.util.Observable);
5770 </code></pre>
5771  * @param {Object} config properties to use (incuding events / listeners)
5772  */
5773
5774 Roo.util.Observable = function(cfg){
5775     
5776     cfg = cfg|| {};
5777     this.addEvents(cfg.events || {});
5778     if (cfg.events) {
5779         delete cfg.events; // make sure
5780     }
5781      
5782     Roo.apply(this, cfg);
5783     
5784     if(this.listeners){
5785         this.on(this.listeners);
5786         delete this.listeners;
5787     }
5788 };
5789 Roo.util.Observable.prototype = {
5790     /** 
5791  * @cfg {Object} listeners  list of events and functions to call for this object, 
5792  * For example :
5793  * <pre><code>
5794     listeners :  { 
5795        'click' : function(e) {
5796            ..... 
5797         } ,
5798         .... 
5799     } 
5800   </code></pre>
5801  */
5802     
5803     
5804     /**
5805      * Fires the specified event with the passed parameters (minus the event name).
5806      * @param {String} eventName
5807      * @param {Object...} args Variable number of parameters are passed to handlers
5808      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5809      */
5810     fireEvent : function(){
5811         var ce = this.events[arguments[0].toLowerCase()];
5812         if(typeof ce == "object"){
5813             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5814         }else{
5815             return true;
5816         }
5817     },
5818
5819     // private
5820     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5821
5822     /**
5823      * Appends an event handler to this component
5824      * @param {String}   eventName The type of event to listen for
5825      * @param {Function} handler The method the event invokes
5826      * @param {Object}   scope (optional) The scope in which to execute the handler
5827      * function. The handler function's "this" context.
5828      * @param {Object}   options (optional) An object containing handler configuration
5829      * properties. This may contain any of the following properties:<ul>
5830      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5831      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5832      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5833      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5834      * by the specified number of milliseconds. If the event fires again within that time, the original
5835      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5836      * </ul><br>
5837      * <p>
5838      * <b>Combining Options</b><br>
5839      * Using the options argument, it is possible to combine different types of listeners:<br>
5840      * <br>
5841      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5842                 <pre><code>
5843                 el.on('click', this.onClick, this, {
5844                         single: true,
5845                 delay: 100,
5846                 forumId: 4
5847                 });
5848                 </code></pre>
5849      * <p>
5850      * <b>Attaching multiple handlers in 1 call</b><br>
5851      * The method also allows for a single argument to be passed which is a config object containing properties
5852      * which specify multiple handlers.
5853      * <pre><code>
5854                 el.on({
5855                         'click': {
5856                         fn: this.onClick,
5857                         scope: this,
5858                         delay: 100
5859                 }, 
5860                 'mouseover': {
5861                         fn: this.onMouseOver,
5862                         scope: this
5863                 },
5864                 'mouseout': {
5865                         fn: this.onMouseOut,
5866                         scope: this
5867                 }
5868                 });
5869                 </code></pre>
5870      * <p>
5871      * Or a shorthand syntax which passes the same scope object to all handlers:
5872         <pre><code>
5873                 el.on({
5874                         'click': this.onClick,
5875                 'mouseover': this.onMouseOver,
5876                 'mouseout': this.onMouseOut,
5877                 scope: this
5878                 });
5879                 </code></pre>
5880      */
5881     addListener : function(eventName, fn, scope, o){
5882         if(typeof eventName == "object"){
5883             o = eventName;
5884             for(var e in o){
5885                 if(this.filterOptRe.test(e)){
5886                     continue;
5887                 }
5888                 if(typeof o[e] == "function"){
5889                     // shared options
5890                     this.addListener(e, o[e], o.scope,  o);
5891                 }else{
5892                     // individual options
5893                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5894                 }
5895             }
5896             return;
5897         }
5898         o = (!o || typeof o == "boolean") ? {} : o;
5899         eventName = eventName.toLowerCase();
5900         var ce = this.events[eventName] || true;
5901         if(typeof ce == "boolean"){
5902             ce = new Roo.util.Event(this, eventName);
5903             this.events[eventName] = ce;
5904         }
5905         ce.addListener(fn, scope, o);
5906     },
5907
5908     /**
5909      * Removes a listener
5910      * @param {String}   eventName     The type of event to listen for
5911      * @param {Function} handler        The handler to remove
5912      * @param {Object}   scope  (optional) The scope (this object) for the handler
5913      */
5914     removeListener : function(eventName, fn, scope){
5915         var ce = this.events[eventName.toLowerCase()];
5916         if(typeof ce == "object"){
5917             ce.removeListener(fn, scope);
5918         }
5919     },
5920
5921     /**
5922      * Removes all listeners for this object
5923      */
5924     purgeListeners : function(){
5925         for(var evt in this.events){
5926             if(typeof this.events[evt] == "object"){
5927                  this.events[evt].clearListeners();
5928             }
5929         }
5930     },
5931
5932     relayEvents : function(o, events){
5933         var createHandler = function(ename){
5934             return function(){
5935                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5936             };
5937         };
5938         for(var i = 0, len = events.length; i < len; i++){
5939             var ename = events[i];
5940             if(!this.events[ename]){ this.events[ename] = true; };
5941             o.on(ename, createHandler(ename), this);
5942         }
5943     },
5944
5945     /**
5946      * Used to define events on this Observable
5947      * @param {Object} object The object with the events defined
5948      */
5949     addEvents : function(o){
5950         if(!this.events){
5951             this.events = {};
5952         }
5953         Roo.applyIf(this.events, o);
5954     },
5955
5956     /**
5957      * Checks to see if this object has any listeners for a specified event
5958      * @param {String} eventName The name of the event to check for
5959      * @return {Boolean} True if the event is being listened for, else false
5960      */
5961     hasListener : function(eventName){
5962         var e = this.events[eventName];
5963         return typeof e == "object" && e.listeners.length > 0;
5964     }
5965 };
5966 /**
5967  * Appends an event handler to this element (shorthand for addListener)
5968  * @param {String}   eventName     The type of event to listen for
5969  * @param {Function} handler        The method the event invokes
5970  * @param {Object}   scope (optional) The scope in which to execute the handler
5971  * function. The handler function's "this" context.
5972  * @param {Object}   options  (optional)
5973  * @method
5974  */
5975 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5976 /**
5977  * Removes a listener (shorthand for removeListener)
5978  * @param {String}   eventName     The type of event to listen for
5979  * @param {Function} handler        The handler to remove
5980  * @param {Object}   scope  (optional) The scope (this object) for the handler
5981  * @method
5982  */
5983 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5984
5985 /**
5986  * Starts capture on the specified Observable. All events will be passed
5987  * to the supplied function with the event name + standard signature of the event
5988  * <b>before</b> the event is fired. If the supplied function returns false,
5989  * the event will not fire.
5990  * @param {Observable} o The Observable to capture
5991  * @param {Function} fn The function to call
5992  * @param {Object} scope (optional) The scope (this object) for the fn
5993  * @static
5994  */
5995 Roo.util.Observable.capture = function(o, fn, scope){
5996     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5997 };
5998
5999 /**
6000  * Removes <b>all</b> added captures from the Observable.
6001  * @param {Observable} o The Observable to release
6002  * @static
6003  */
6004 Roo.util.Observable.releaseCapture = function(o){
6005     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6006 };
6007
6008 (function(){
6009
6010     var createBuffered = function(h, o, scope){
6011         var task = new Roo.util.DelayedTask();
6012         return function(){
6013             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6014         };
6015     };
6016
6017     var createSingle = function(h, e, fn, scope){
6018         return function(){
6019             e.removeListener(fn, scope);
6020             return h.apply(scope, arguments);
6021         };
6022     };
6023
6024     var createDelayed = function(h, o, scope){
6025         return function(){
6026             var args = Array.prototype.slice.call(arguments, 0);
6027             setTimeout(function(){
6028                 h.apply(scope, args);
6029             }, o.delay || 10);
6030         };
6031     };
6032
6033     Roo.util.Event = function(obj, name){
6034         this.name = name;
6035         this.obj = obj;
6036         this.listeners = [];
6037     };
6038
6039     Roo.util.Event.prototype = {
6040         addListener : function(fn, scope, options){
6041             var o = options || {};
6042             scope = scope || this.obj;
6043             if(!this.isListening(fn, scope)){
6044                 var l = {fn: fn, scope: scope, options: o};
6045                 var h = fn;
6046                 if(o.delay){
6047                     h = createDelayed(h, o, scope);
6048                 }
6049                 if(o.single){
6050                     h = createSingle(h, this, fn, scope);
6051                 }
6052                 if(o.buffer){
6053                     h = createBuffered(h, o, scope);
6054                 }
6055                 l.fireFn = h;
6056                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6057                     this.listeners.push(l);
6058                 }else{
6059                     this.listeners = this.listeners.slice(0);
6060                     this.listeners.push(l);
6061                 }
6062             }
6063         },
6064
6065         findListener : function(fn, scope){
6066             scope = scope || this.obj;
6067             var ls = this.listeners;
6068             for(var i = 0, len = ls.length; i < len; i++){
6069                 var l = ls[i];
6070                 if(l.fn == fn && l.scope == scope){
6071                     return i;
6072                 }
6073             }
6074             return -1;
6075         },
6076
6077         isListening : function(fn, scope){
6078             return this.findListener(fn, scope) != -1;
6079         },
6080
6081         removeListener : function(fn, scope){
6082             var index;
6083             if((index = this.findListener(fn, scope)) != -1){
6084                 if(!this.firing){
6085                     this.listeners.splice(index, 1);
6086                 }else{
6087                     this.listeners = this.listeners.slice(0);
6088                     this.listeners.splice(index, 1);
6089                 }
6090                 return true;
6091             }
6092             return false;
6093         },
6094
6095         clearListeners : function(){
6096             this.listeners = [];
6097         },
6098
6099         fire : function(){
6100             var ls = this.listeners, scope, len = ls.length;
6101             if(len > 0){
6102                 this.firing = true;
6103                 var args = Array.prototype.slice.call(arguments, 0);                
6104                 for(var i = 0; i < len; i++){
6105                     var l = ls[i];
6106                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6107                         this.firing = false;
6108                         return false;
6109                     }
6110                 }
6111                 this.firing = false;
6112             }
6113             return true;
6114         }
6115     };
6116 })();/*
6117  * RooJS Library 
6118  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6119  *
6120  * Licence LGPL 
6121  *
6122  */
6123  
6124 /**
6125  * @class Roo.Document
6126  * @extends Roo.util.Observable
6127  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6128  * 
6129  * @param {Object} config the methods and properties of the 'base' class for the application.
6130  * 
6131  *  Generic Page handler - implement this to start your app..
6132  * 
6133  * eg.
6134  *  MyProject = new Roo.Document({
6135         events : {
6136             'load' : true // your events..
6137         },
6138         listeners : {
6139             'ready' : function() {
6140                 // fired on Roo.onReady()
6141             }
6142         }
6143  * 
6144  */
6145 Roo.Document = function(cfg) {
6146      
6147     this.addEvents({ 
6148         'ready' : true
6149     });
6150     Roo.util.Observable.call(this,cfg);
6151     
6152     var _this = this;
6153     
6154     Roo.onReady(function() {
6155         _this.fireEvent('ready');
6156     },null,false);
6157     
6158     
6159 }
6160
6161 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6162  * Based on:
6163  * Ext JS Library 1.1.1
6164  * Copyright(c) 2006-2007, Ext JS, LLC.
6165  *
6166  * Originally Released Under LGPL - original licence link has changed is not relivant.
6167  *
6168  * Fork - LGPL
6169  * <script type="text/javascript">
6170  */
6171
6172 /**
6173  * @class Roo.EventManager
6174  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6175  * several useful events directly.
6176  * See {@link Roo.EventObject} for more details on normalized event objects.
6177  * @singleton
6178  */
6179 Roo.EventManager = function(){
6180     var docReadyEvent, docReadyProcId, docReadyState = false;
6181     var resizeEvent, resizeTask, textEvent, textSize;
6182     var E = Roo.lib.Event;
6183     var D = Roo.lib.Dom;
6184
6185     
6186     
6187
6188     var fireDocReady = function(){
6189         if(!docReadyState){
6190             docReadyState = true;
6191             Roo.isReady = true;
6192             if(docReadyProcId){
6193                 clearInterval(docReadyProcId);
6194             }
6195             if(Roo.isGecko || Roo.isOpera) {
6196                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6197             }
6198             if(Roo.isIE){
6199                 var defer = document.getElementById("ie-deferred-loader");
6200                 if(defer){
6201                     defer.onreadystatechange = null;
6202                     defer.parentNode.removeChild(defer);
6203                 }
6204             }
6205             if(docReadyEvent){
6206                 docReadyEvent.fire();
6207                 docReadyEvent.clearListeners();
6208             }
6209         }
6210     };
6211     
6212     var initDocReady = function(){
6213         docReadyEvent = new Roo.util.Event();
6214         if(Roo.isGecko || Roo.isOpera) {
6215             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6216         }else if(Roo.isIE){
6217             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6218             var defer = document.getElementById("ie-deferred-loader");
6219             defer.onreadystatechange = function(){
6220                 if(this.readyState == "complete"){
6221                     fireDocReady();
6222                 }
6223             };
6224         }else if(Roo.isSafari){ 
6225             docReadyProcId = setInterval(function(){
6226                 var rs = document.readyState;
6227                 if(rs == "complete") {
6228                     fireDocReady();     
6229                  }
6230             }, 10);
6231         }
6232         // no matter what, make sure it fires on load
6233         E.on(window, "load", fireDocReady);
6234     };
6235
6236     var createBuffered = function(h, o){
6237         var task = new Roo.util.DelayedTask(h);
6238         return function(e){
6239             // create new event object impl so new events don't wipe out properties
6240             e = new Roo.EventObjectImpl(e);
6241             task.delay(o.buffer, h, null, [e]);
6242         };
6243     };
6244
6245     var createSingle = function(h, el, ename, fn){
6246         return function(e){
6247             Roo.EventManager.removeListener(el, ename, fn);
6248             h(e);
6249         };
6250     };
6251
6252     var createDelayed = function(h, o){
6253         return function(e){
6254             // create new event object impl so new events don't wipe out properties
6255             e = new Roo.EventObjectImpl(e);
6256             setTimeout(function(){
6257                 h(e);
6258             }, o.delay || 10);
6259         };
6260     };
6261     var transitionEndVal = false;
6262     
6263     var transitionEnd = function()
6264     {
6265         if (transitionEndVal) {
6266             return transitionEndVal;
6267         }
6268         var el = document.createElement('div');
6269
6270         var transEndEventNames = {
6271             WebkitTransition : 'webkitTransitionEnd',
6272             MozTransition    : 'transitionend',
6273             OTransition      : 'oTransitionEnd otransitionend',
6274             transition       : 'transitionend'
6275         };
6276     
6277         for (var name in transEndEventNames) {
6278             if (el.style[name] !== undefined) {
6279                 transitionEndVal = transEndEventNames[name];
6280                 return  transitionEndVal ;
6281             }
6282         }
6283     }
6284     
6285
6286     var listen = function(element, ename, opt, fn, scope){
6287         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6288         fn = fn || o.fn; scope = scope || o.scope;
6289         var el = Roo.getDom(element);
6290         
6291         
6292         if(!el){
6293             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6294         }
6295         
6296         if (ename == 'transitionend') {
6297             ename = transitionEnd();
6298         }
6299         var h = function(e){
6300             e = Roo.EventObject.setEvent(e);
6301             var t;
6302             if(o.delegate){
6303                 t = e.getTarget(o.delegate, el);
6304                 if(!t){
6305                     return;
6306                 }
6307             }else{
6308                 t = e.target;
6309             }
6310             if(o.stopEvent === true){
6311                 e.stopEvent();
6312             }
6313             if(o.preventDefault === true){
6314                e.preventDefault();
6315             }
6316             if(o.stopPropagation === true){
6317                 e.stopPropagation();
6318             }
6319
6320             if(o.normalized === false){
6321                 e = e.browserEvent;
6322             }
6323
6324             fn.call(scope || el, e, t, o);
6325         };
6326         if(o.delay){
6327             h = createDelayed(h, o);
6328         }
6329         if(o.single){
6330             h = createSingle(h, el, ename, fn);
6331         }
6332         if(o.buffer){
6333             h = createBuffered(h, o);
6334         }
6335         
6336         fn._handlers = fn._handlers || [];
6337         
6338         
6339         fn._handlers.push([Roo.id(el), ename, h]);
6340         
6341         
6342          
6343         E.on(el, ename, h);
6344         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6345             el.addEventListener("DOMMouseScroll", h, false);
6346             E.on(window, 'unload', function(){
6347                 el.removeEventListener("DOMMouseScroll", h, false);
6348             });
6349         }
6350         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6351             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6352         }
6353         return h;
6354     };
6355
6356     var stopListening = function(el, ename, fn){
6357         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6358         if(hds){
6359             for(var i = 0, len = hds.length; i < len; i++){
6360                 var h = hds[i];
6361                 if(h[0] == id && h[1] == ename){
6362                     hd = h[2];
6363                     hds.splice(i, 1);
6364                     break;
6365                 }
6366             }
6367         }
6368         E.un(el, ename, hd);
6369         el = Roo.getDom(el);
6370         if(ename == "mousewheel" && el.addEventListener){
6371             el.removeEventListener("DOMMouseScroll", hd, false);
6372         }
6373         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6374             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6375         }
6376     };
6377
6378     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6379     
6380     var pub = {
6381         
6382         
6383         /** 
6384          * Fix for doc tools
6385          * @scope Roo.EventManager
6386          */
6387         
6388         
6389         /** 
6390          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6391          * object with a Roo.EventObject
6392          * @param {Function} fn        The method the event invokes
6393          * @param {Object}   scope    An object that becomes the scope of the handler
6394          * @param {boolean}  override If true, the obj passed in becomes
6395          *                             the execution scope of the listener
6396          * @return {Function} The wrapped function
6397          * @deprecated
6398          */
6399         wrap : function(fn, scope, override){
6400             return function(e){
6401                 Roo.EventObject.setEvent(e);
6402                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6403             };
6404         },
6405         
6406         /**
6407      * Appends an event handler to an element (shorthand for addListener)
6408      * @param {String/HTMLElement}   element        The html element or id to assign the
6409      * @param {String}   eventName The type of event to listen for
6410      * @param {Function} handler The method the event invokes
6411      * @param {Object}   scope (optional) The scope in which to execute the handler
6412      * function. The handler function's "this" context.
6413      * @param {Object}   options (optional) An object containing handler configuration
6414      * properties. This may contain any of the following properties:<ul>
6415      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6416      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6417      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6418      * <li>preventDefault {Boolean} True to prevent the default action</li>
6419      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6420      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6421      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6422      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6423      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6424      * by the specified number of milliseconds. If the event fires again within that time, the original
6425      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6426      * </ul><br>
6427      * <p>
6428      * <b>Combining Options</b><br>
6429      * Using the options argument, it is possible to combine different types of listeners:<br>
6430      * <br>
6431      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6432      * Code:<pre><code>
6433 el.on('click', this.onClick, this, {
6434     single: true,
6435     delay: 100,
6436     stopEvent : true,
6437     forumId: 4
6438 });</code></pre>
6439      * <p>
6440      * <b>Attaching multiple handlers in 1 call</b><br>
6441       * The method also allows for a single argument to be passed which is a config object containing properties
6442      * which specify multiple handlers.
6443      * <p>
6444      * Code:<pre><code>
6445 el.on({
6446     'click' : {
6447         fn: this.onClick
6448         scope: this,
6449         delay: 100
6450     },
6451     'mouseover' : {
6452         fn: this.onMouseOver
6453         scope: this
6454     },
6455     'mouseout' : {
6456         fn: this.onMouseOut
6457         scope: this
6458     }
6459 });</code></pre>
6460      * <p>
6461      * Or a shorthand syntax:<br>
6462      * Code:<pre><code>
6463 el.on({
6464     'click' : this.onClick,
6465     'mouseover' : this.onMouseOver,
6466     'mouseout' : this.onMouseOut
6467     scope: this
6468 });</code></pre>
6469      */
6470         addListener : function(element, eventName, fn, scope, options){
6471             if(typeof eventName == "object"){
6472                 var o = eventName;
6473                 for(var e in o){
6474                     if(propRe.test(e)){
6475                         continue;
6476                     }
6477                     if(typeof o[e] == "function"){
6478                         // shared options
6479                         listen(element, e, o, o[e], o.scope);
6480                     }else{
6481                         // individual options
6482                         listen(element, e, o[e]);
6483                     }
6484                 }
6485                 return;
6486             }
6487             return listen(element, eventName, options, fn, scope);
6488         },
6489         
6490         /**
6491          * Removes an event handler
6492          *
6493          * @param {String/HTMLElement}   element        The id or html element to remove the 
6494          *                             event from
6495          * @param {String}   eventName     The type of event
6496          * @param {Function} fn
6497          * @return {Boolean} True if a listener was actually removed
6498          */
6499         removeListener : function(element, eventName, fn){
6500             return stopListening(element, eventName, fn);
6501         },
6502         
6503         /**
6504          * Fires when the document is ready (before onload and before images are loaded). Can be 
6505          * accessed shorthanded Roo.onReady().
6506          * @param {Function} fn        The method the event invokes
6507          * @param {Object}   scope    An  object that becomes the scope of the handler
6508          * @param {boolean}  options
6509          */
6510         onDocumentReady : function(fn, scope, options){
6511             if(docReadyState){ // if it already fired
6512                 docReadyEvent.addListener(fn, scope, options);
6513                 docReadyEvent.fire();
6514                 docReadyEvent.clearListeners();
6515                 return;
6516             }
6517             if(!docReadyEvent){
6518                 initDocReady();
6519             }
6520             docReadyEvent.addListener(fn, scope, options);
6521         },
6522         
6523         /**
6524          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6525          * @param {Function} fn        The method the event invokes
6526          * @param {Object}   scope    An object that becomes the scope of the handler
6527          * @param {boolean}  options
6528          */
6529         onWindowResize : function(fn, scope, options){
6530             if(!resizeEvent){
6531                 resizeEvent = new Roo.util.Event();
6532                 resizeTask = new Roo.util.DelayedTask(function(){
6533                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6534                 });
6535                 E.on(window, "resize", function(){
6536                     if(Roo.isIE){
6537                         resizeTask.delay(50);
6538                     }else{
6539                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6540                     }
6541                 });
6542             }
6543             resizeEvent.addListener(fn, scope, options);
6544         },
6545
6546         /**
6547          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6548          * @param {Function} fn        The method the event invokes
6549          * @param {Object}   scope    An object that becomes the scope of the handler
6550          * @param {boolean}  options
6551          */
6552         onTextResize : function(fn, scope, options){
6553             if(!textEvent){
6554                 textEvent = new Roo.util.Event();
6555                 var textEl = new Roo.Element(document.createElement('div'));
6556                 textEl.dom.className = 'x-text-resize';
6557                 textEl.dom.innerHTML = 'X';
6558                 textEl.appendTo(document.body);
6559                 textSize = textEl.dom.offsetHeight;
6560                 setInterval(function(){
6561                     if(textEl.dom.offsetHeight != textSize){
6562                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6563                     }
6564                 }, this.textResizeInterval);
6565             }
6566             textEvent.addListener(fn, scope, options);
6567         },
6568
6569         /**
6570          * Removes the passed window resize listener.
6571          * @param {Function} fn        The method the event invokes
6572          * @param {Object}   scope    The scope of handler
6573          */
6574         removeResizeListener : function(fn, scope){
6575             if(resizeEvent){
6576                 resizeEvent.removeListener(fn, scope);
6577             }
6578         },
6579
6580         // private
6581         fireResize : function(){
6582             if(resizeEvent){
6583                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6584             }   
6585         },
6586         /**
6587          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6588          */
6589         ieDeferSrc : false,
6590         /**
6591          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6592          */
6593         textResizeInterval : 50
6594     };
6595     
6596     /**
6597      * Fix for doc tools
6598      * @scopeAlias pub=Roo.EventManager
6599      */
6600     
6601      /**
6602      * Appends an event handler to an element (shorthand for addListener)
6603      * @param {String/HTMLElement}   element        The html element or id to assign the
6604      * @param {String}   eventName The type of event to listen for
6605      * @param {Function} handler The method the event invokes
6606      * @param {Object}   scope (optional) The scope in which to execute the handler
6607      * function. The handler function's "this" context.
6608      * @param {Object}   options (optional) An object containing handler configuration
6609      * properties. This may contain any of the following properties:<ul>
6610      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6611      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6612      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6613      * <li>preventDefault {Boolean} True to prevent the default action</li>
6614      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6615      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6616      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6617      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6618      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6619      * by the specified number of milliseconds. If the event fires again within that time, the original
6620      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6621      * </ul><br>
6622      * <p>
6623      * <b>Combining Options</b><br>
6624      * Using the options argument, it is possible to combine different types of listeners:<br>
6625      * <br>
6626      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6627      * Code:<pre><code>
6628 el.on('click', this.onClick, this, {
6629     single: true,
6630     delay: 100,
6631     stopEvent : true,
6632     forumId: 4
6633 });</code></pre>
6634      * <p>
6635      * <b>Attaching multiple handlers in 1 call</b><br>
6636       * The method also allows for a single argument to be passed which is a config object containing properties
6637      * which specify multiple handlers.
6638      * <p>
6639      * Code:<pre><code>
6640 el.on({
6641     'click' : {
6642         fn: this.onClick
6643         scope: this,
6644         delay: 100
6645     },
6646     'mouseover' : {
6647         fn: this.onMouseOver
6648         scope: this
6649     },
6650     'mouseout' : {
6651         fn: this.onMouseOut
6652         scope: this
6653     }
6654 });</code></pre>
6655      * <p>
6656      * Or a shorthand syntax:<br>
6657      * Code:<pre><code>
6658 el.on({
6659     'click' : this.onClick,
6660     'mouseover' : this.onMouseOver,
6661     'mouseout' : this.onMouseOut
6662     scope: this
6663 });</code></pre>
6664      */
6665     pub.on = pub.addListener;
6666     pub.un = pub.removeListener;
6667
6668     pub.stoppedMouseDownEvent = new Roo.util.Event();
6669     return pub;
6670 }();
6671 /**
6672   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6673   * @param {Function} fn        The method the event invokes
6674   * @param {Object}   scope    An  object that becomes the scope of the handler
6675   * @param {boolean}  override If true, the obj passed in becomes
6676   *                             the execution scope of the listener
6677   * @member Roo
6678   * @method onReady
6679  */
6680 Roo.onReady = Roo.EventManager.onDocumentReady;
6681
6682 Roo.onReady(function(){
6683     var bd = Roo.get(document.body);
6684     if(!bd){ return; }
6685
6686     var cls = [
6687             Roo.isIE ? "roo-ie"
6688             : Roo.isIE11 ? "roo-ie11"
6689             : Roo.isEdge ? "roo-edge"
6690             : Roo.isGecko ? "roo-gecko"
6691             : Roo.isOpera ? "roo-opera"
6692             : Roo.isSafari ? "roo-safari" : ""];
6693
6694     if(Roo.isMac){
6695         cls.push("roo-mac");
6696     }
6697     if(Roo.isLinux){
6698         cls.push("roo-linux");
6699     }
6700     if(Roo.isIOS){
6701         cls.push("roo-ios");
6702     }
6703     if(Roo.isTouch){
6704         cls.push("roo-touch");
6705     }
6706     if(Roo.isBorderBox){
6707         cls.push('roo-border-box');
6708     }
6709     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6710         var p = bd.dom.parentNode;
6711         if(p){
6712             p.className += ' roo-strict';
6713         }
6714     }
6715     bd.addClass(cls.join(' '));
6716 });
6717
6718 /**
6719  * @class Roo.EventObject
6720  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6721  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6722  * Example:
6723  * <pre><code>
6724  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6725     e.preventDefault();
6726     var target = e.getTarget();
6727     ...
6728  }
6729  var myDiv = Roo.get("myDiv");
6730  myDiv.on("click", handleClick);
6731  //or
6732  Roo.EventManager.on("myDiv", 'click', handleClick);
6733  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6734  </code></pre>
6735  * @singleton
6736  */
6737 Roo.EventObject = function(){
6738     
6739     var E = Roo.lib.Event;
6740     
6741     // safari keypress events for special keys return bad keycodes
6742     var safariKeys = {
6743         63234 : 37, // left
6744         63235 : 39, // right
6745         63232 : 38, // up
6746         63233 : 40, // down
6747         63276 : 33, // page up
6748         63277 : 34, // page down
6749         63272 : 46, // delete
6750         63273 : 36, // home
6751         63275 : 35  // end
6752     };
6753
6754     // normalize button clicks
6755     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6756                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6757
6758     Roo.EventObjectImpl = function(e){
6759         if(e){
6760             this.setEvent(e.browserEvent || e);
6761         }
6762     };
6763     Roo.EventObjectImpl.prototype = {
6764         /**
6765          * Used to fix doc tools.
6766          * @scope Roo.EventObject.prototype
6767          */
6768             
6769
6770         
6771         
6772         /** The normal browser event */
6773         browserEvent : null,
6774         /** The button pressed in a mouse event */
6775         button : -1,
6776         /** True if the shift key was down during the event */
6777         shiftKey : false,
6778         /** True if the control key was down during the event */
6779         ctrlKey : false,
6780         /** True if the alt key was down during the event */
6781         altKey : false,
6782
6783         /** Key constant 
6784         * @type Number */
6785         BACKSPACE : 8,
6786         /** Key constant 
6787         * @type Number */
6788         TAB : 9,
6789         /** Key constant 
6790         * @type Number */
6791         RETURN : 13,
6792         /** Key constant 
6793         * @type Number */
6794         ENTER : 13,
6795         /** Key constant 
6796         * @type Number */
6797         SHIFT : 16,
6798         /** Key constant 
6799         * @type Number */
6800         CONTROL : 17,
6801         /** Key constant 
6802         * @type Number */
6803         ESC : 27,
6804         /** Key constant 
6805         * @type Number */
6806         SPACE : 32,
6807         /** Key constant 
6808         * @type Number */
6809         PAGEUP : 33,
6810         /** Key constant 
6811         * @type Number */
6812         PAGEDOWN : 34,
6813         /** Key constant 
6814         * @type Number */
6815         END : 35,
6816         /** Key constant 
6817         * @type Number */
6818         HOME : 36,
6819         /** Key constant 
6820         * @type Number */
6821         LEFT : 37,
6822         /** Key constant 
6823         * @type Number */
6824         UP : 38,
6825         /** Key constant 
6826         * @type Number */
6827         RIGHT : 39,
6828         /** Key constant 
6829         * @type Number */
6830         DOWN : 40,
6831         /** Key constant 
6832         * @type Number */
6833         DELETE : 46,
6834         /** Key constant 
6835         * @type Number */
6836         F5 : 116,
6837
6838            /** @private */
6839         setEvent : function(e){
6840             if(e == this || (e && e.browserEvent)){ // already wrapped
6841                 return e;
6842             }
6843             this.browserEvent = e;
6844             if(e){
6845                 // normalize buttons
6846                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6847                 if(e.type == 'click' && this.button == -1){
6848                     this.button = 0;
6849                 }
6850                 this.type = e.type;
6851                 this.shiftKey = e.shiftKey;
6852                 // mac metaKey behaves like ctrlKey
6853                 this.ctrlKey = e.ctrlKey || e.metaKey;
6854                 this.altKey = e.altKey;
6855                 // in getKey these will be normalized for the mac
6856                 this.keyCode = e.keyCode;
6857                 // keyup warnings on firefox.
6858                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6859                 // cache the target for the delayed and or buffered events
6860                 this.target = E.getTarget(e);
6861                 // same for XY
6862                 this.xy = E.getXY(e);
6863             }else{
6864                 this.button = -1;
6865                 this.shiftKey = false;
6866                 this.ctrlKey = false;
6867                 this.altKey = false;
6868                 this.keyCode = 0;
6869                 this.charCode =0;
6870                 this.target = null;
6871                 this.xy = [0, 0];
6872             }
6873             return this;
6874         },
6875
6876         /**
6877          * Stop the event (preventDefault and stopPropagation)
6878          */
6879         stopEvent : function(){
6880             if(this.browserEvent){
6881                 if(this.browserEvent.type == 'mousedown'){
6882                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6883                 }
6884                 E.stopEvent(this.browserEvent);
6885             }
6886         },
6887
6888         /**
6889          * Prevents the browsers default handling of the event.
6890          */
6891         preventDefault : function(){
6892             if(this.browserEvent){
6893                 E.preventDefault(this.browserEvent);
6894             }
6895         },
6896
6897         /** @private */
6898         isNavKeyPress : function(){
6899             var k = this.keyCode;
6900             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6901             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6902         },
6903
6904         isSpecialKey : function(){
6905             var k = this.keyCode;
6906             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6907             (k == 16) || (k == 17) ||
6908             (k >= 18 && k <= 20) ||
6909             (k >= 33 && k <= 35) ||
6910             (k >= 36 && k <= 39) ||
6911             (k >= 44 && k <= 45);
6912         },
6913         /**
6914          * Cancels bubbling of the event.
6915          */
6916         stopPropagation : function(){
6917             if(this.browserEvent){
6918                 if(this.type == 'mousedown'){
6919                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6920                 }
6921                 E.stopPropagation(this.browserEvent);
6922             }
6923         },
6924
6925         /**
6926          * Gets the key code for the event.
6927          * @return {Number}
6928          */
6929         getCharCode : function(){
6930             return this.charCode || this.keyCode;
6931         },
6932
6933         /**
6934          * Returns a normalized keyCode for the event.
6935          * @return {Number} The key code
6936          */
6937         getKey : function(){
6938             var k = this.keyCode || this.charCode;
6939             return Roo.isSafari ? (safariKeys[k] || k) : k;
6940         },
6941
6942         /**
6943          * Gets the x coordinate of the event.
6944          * @return {Number}
6945          */
6946         getPageX : function(){
6947             return this.xy[0];
6948         },
6949
6950         /**
6951          * Gets the y coordinate of the event.
6952          * @return {Number}
6953          */
6954         getPageY : function(){
6955             return this.xy[1];
6956         },
6957
6958         /**
6959          * Gets the time of the event.
6960          * @return {Number}
6961          */
6962         getTime : function(){
6963             if(this.browserEvent){
6964                 return E.getTime(this.browserEvent);
6965             }
6966             return null;
6967         },
6968
6969         /**
6970          * Gets the page coordinates of the event.
6971          * @return {Array} The xy values like [x, y]
6972          */
6973         getXY : function(){
6974             return this.xy;
6975         },
6976
6977         /**
6978          * Gets the target for the event.
6979          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6980          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6981                 search as a number or element (defaults to 10 || document.body)
6982          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6983          * @return {HTMLelement}
6984          */
6985         getTarget : function(selector, maxDepth, returnEl){
6986             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6987         },
6988         /**
6989          * Gets the related target.
6990          * @return {HTMLElement}
6991          */
6992         getRelatedTarget : function(){
6993             if(this.browserEvent){
6994                 return E.getRelatedTarget(this.browserEvent);
6995             }
6996             return null;
6997         },
6998
6999         /**
7000          * Normalizes mouse wheel delta across browsers
7001          * @return {Number} The delta
7002          */
7003         getWheelDelta : function(){
7004             var e = this.browserEvent;
7005             var delta = 0;
7006             if(e.wheelDelta){ /* IE/Opera. */
7007                 delta = e.wheelDelta/120;
7008             }else if(e.detail){ /* Mozilla case. */
7009                 delta = -e.detail/3;
7010             }
7011             return delta;
7012         },
7013
7014         /**
7015          * Returns true if the control, meta, shift or alt key was pressed during this event.
7016          * @return {Boolean}
7017          */
7018         hasModifier : function(){
7019             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7020         },
7021
7022         /**
7023          * Returns true if the target of this event equals el or is a child of el
7024          * @param {String/HTMLElement/Element} el
7025          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7026          * @return {Boolean}
7027          */
7028         within : function(el, related){
7029             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7030             return t && Roo.fly(el).contains(t);
7031         },
7032
7033         getPoint : function(){
7034             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7035         }
7036     };
7037
7038     return new Roo.EventObjectImpl();
7039 }();
7040             
7041     /*
7042  * Based on:
7043  * Ext JS Library 1.1.1
7044  * Copyright(c) 2006-2007, Ext JS, LLC.
7045  *
7046  * Originally Released Under LGPL - original licence link has changed is not relivant.
7047  *
7048  * Fork - LGPL
7049  * <script type="text/javascript">
7050  */
7051
7052  
7053 // was in Composite Element!??!?!
7054  
7055 (function(){
7056     var D = Roo.lib.Dom;
7057     var E = Roo.lib.Event;
7058     var A = Roo.lib.Anim;
7059
7060     // local style camelizing for speed
7061     var propCache = {};
7062     var camelRe = /(-[a-z])/gi;
7063     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7064     var view = document.defaultView;
7065
7066 /**
7067  * @class Roo.Element
7068  * Represents an Element in the DOM.<br><br>
7069  * Usage:<br>
7070 <pre><code>
7071 var el = Roo.get("my-div");
7072
7073 // or with getEl
7074 var el = getEl("my-div");
7075
7076 // or with a DOM element
7077 var el = Roo.get(myDivElement);
7078 </code></pre>
7079  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7080  * each call instead of constructing a new one.<br><br>
7081  * <b>Animations</b><br />
7082  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7083  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7084 <pre>
7085 Option    Default   Description
7086 --------- --------  ---------------------------------------------
7087 duration  .35       The duration of the animation in seconds
7088 easing    easeOut   The YUI easing method
7089 callback  none      A function to execute when the anim completes
7090 scope     this      The scope (this) of the callback function
7091 </pre>
7092 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7093 * manipulate the animation. Here's an example:
7094 <pre><code>
7095 var el = Roo.get("my-div");
7096
7097 // no animation
7098 el.setWidth(100);
7099
7100 // default animation
7101 el.setWidth(100, true);
7102
7103 // animation with some options set
7104 el.setWidth(100, {
7105     duration: 1,
7106     callback: this.foo,
7107     scope: this
7108 });
7109
7110 // using the "anim" property to get the Anim object
7111 var opt = {
7112     duration: 1,
7113     callback: this.foo,
7114     scope: this
7115 };
7116 el.setWidth(100, opt);
7117 ...
7118 if(opt.anim.isAnimated()){
7119     opt.anim.stop();
7120 }
7121 </code></pre>
7122 * <b> Composite (Collections of) Elements</b><br />
7123  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7124  * @constructor Create a new Element directly.
7125  * @param {String/HTMLElement} element
7126  * @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).
7127  */
7128     Roo.Element = function(element, forceNew){
7129         var dom = typeof element == "string" ?
7130                 document.getElementById(element) : element;
7131         if(!dom){ // invalid id/element
7132             return null;
7133         }
7134         var id = dom.id;
7135         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7136             return Roo.Element.cache[id];
7137         }
7138
7139         /**
7140          * The DOM element
7141          * @type HTMLElement
7142          */
7143         this.dom = dom;
7144
7145         /**
7146          * The DOM element ID
7147          * @type String
7148          */
7149         this.id = id || Roo.id(dom);
7150     };
7151
7152     var El = Roo.Element;
7153
7154     El.prototype = {
7155         /**
7156          * The element's default display mode  (defaults to "") 
7157          * @type String
7158          */
7159         originalDisplay : "",
7160
7161         
7162         // note this is overridden in BS version..
7163         visibilityMode : 1, 
7164         /**
7165          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7166          * @type String
7167          */
7168         defaultUnit : "px",
7169         
7170         /**
7171          * Sets the element's visibility mode. When setVisible() is called it
7172          * will use this to determine whether to set the visibility or the display property.
7173          * @param visMode Element.VISIBILITY or Element.DISPLAY
7174          * @return {Roo.Element} this
7175          */
7176         setVisibilityMode : function(visMode){
7177             this.visibilityMode = visMode;
7178             return this;
7179         },
7180         /**
7181          * Convenience method for setVisibilityMode(Element.DISPLAY)
7182          * @param {String} display (optional) What to set display to when visible
7183          * @return {Roo.Element} this
7184          */
7185         enableDisplayMode : function(display){
7186             this.setVisibilityMode(El.DISPLAY);
7187             if(typeof display != "undefined") { this.originalDisplay = display; }
7188             return this;
7189         },
7190
7191         /**
7192          * 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)
7193          * @param {String} selector The simple selector to test
7194          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7195                 search as a number or element (defaults to 10 || document.body)
7196          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7197          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7198          */
7199         findParent : function(simpleSelector, maxDepth, returnEl){
7200             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7201             maxDepth = maxDepth || 50;
7202             if(typeof maxDepth != "number"){
7203                 stopEl = Roo.getDom(maxDepth);
7204                 maxDepth = 10;
7205             }
7206             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7207                 if(dq.is(p, simpleSelector)){
7208                     return returnEl ? Roo.get(p) : p;
7209                 }
7210                 depth++;
7211                 p = p.parentNode;
7212             }
7213             return null;
7214         },
7215
7216
7217         /**
7218          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7219          * @param {String} selector The simple selector to test
7220          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7221                 search as a number or element (defaults to 10 || document.body)
7222          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7223          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7224          */
7225         findParentNode : function(simpleSelector, maxDepth, returnEl){
7226             var p = Roo.fly(this.dom.parentNode, '_internal');
7227             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7228         },
7229         
7230         /**
7231          * Looks at  the scrollable parent element
7232          */
7233         findScrollableParent : function()
7234         {
7235             var overflowRegex = /(auto|scroll)/;
7236             
7237             if(this.getStyle('position') === 'fixed'){
7238                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7239             }
7240             
7241             var excludeStaticParent = this.getStyle('position') === "absolute";
7242             
7243             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7244                 
7245                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7246                     continue;
7247                 }
7248                 
7249                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7250                     return parent;
7251                 }
7252                 
7253                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7254                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7255                 }
7256             }
7257             
7258             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7259         },
7260
7261         /**
7262          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7263          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7264          * @param {String} selector The simple selector to test
7265          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7266                 search as a number or element (defaults to 10 || document.body)
7267          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7268          */
7269         up : function(simpleSelector, maxDepth){
7270             return this.findParentNode(simpleSelector, maxDepth, true);
7271         },
7272
7273
7274
7275         /**
7276          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7277          * @param {String} selector The simple selector to test
7278          * @return {Boolean} True if this element matches the selector, else false
7279          */
7280         is : function(simpleSelector){
7281             return Roo.DomQuery.is(this.dom, simpleSelector);
7282         },
7283
7284         /**
7285          * Perform animation on this element.
7286          * @param {Object} args The YUI animation control args
7287          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7288          * @param {Function} onComplete (optional) Function to call when animation completes
7289          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7290          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7291          * @return {Roo.Element} this
7292          */
7293         animate : function(args, duration, onComplete, easing, animType){
7294             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7295             return this;
7296         },
7297
7298         /*
7299          * @private Internal animation call
7300          */
7301         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7302             animType = animType || 'run';
7303             opt = opt || {};
7304             var anim = Roo.lib.Anim[animType](
7305                 this.dom, args,
7306                 (opt.duration || defaultDur) || .35,
7307                 (opt.easing || defaultEase) || 'easeOut',
7308                 function(){
7309                     Roo.callback(cb, this);
7310                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7311                 },
7312                 this
7313             );
7314             opt.anim = anim;
7315             return anim;
7316         },
7317
7318         // private legacy anim prep
7319         preanim : function(a, i){
7320             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7321         },
7322
7323         /**
7324          * Removes worthless text nodes
7325          * @param {Boolean} forceReclean (optional) By default the element
7326          * keeps track if it has been cleaned already so
7327          * you can call this over and over. However, if you update the element and
7328          * need to force a reclean, you can pass true.
7329          */
7330         clean : function(forceReclean){
7331             if(this.isCleaned && forceReclean !== true){
7332                 return this;
7333             }
7334             var ns = /\S/;
7335             var d = this.dom, n = d.firstChild, ni = -1;
7336             while(n){
7337                 var nx = n.nextSibling;
7338                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7339                     d.removeChild(n);
7340                 }else{
7341                     n.nodeIndex = ++ni;
7342                 }
7343                 n = nx;
7344             }
7345             this.isCleaned = true;
7346             return this;
7347         },
7348
7349         // private
7350         calcOffsetsTo : function(el){
7351             el = Roo.get(el);
7352             var d = el.dom;
7353             var restorePos = false;
7354             if(el.getStyle('position') == 'static'){
7355                 el.position('relative');
7356                 restorePos = true;
7357             }
7358             var x = 0, y =0;
7359             var op = this.dom;
7360             while(op && op != d && op.tagName != 'HTML'){
7361                 x+= op.offsetLeft;
7362                 y+= op.offsetTop;
7363                 op = op.offsetParent;
7364             }
7365             if(restorePos){
7366                 el.position('static');
7367             }
7368             return [x, y];
7369         },
7370
7371         /**
7372          * Scrolls this element into view within the passed container.
7373          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7374          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7375          * @return {Roo.Element} this
7376          */
7377         scrollIntoView : function(container, hscroll){
7378             var c = Roo.getDom(container) || document.body;
7379             var el = this.dom;
7380
7381             var o = this.calcOffsetsTo(c),
7382                 l = o[0],
7383                 t = o[1],
7384                 b = t+el.offsetHeight,
7385                 r = l+el.offsetWidth;
7386
7387             var ch = c.clientHeight;
7388             var ct = parseInt(c.scrollTop, 10);
7389             var cl = parseInt(c.scrollLeft, 10);
7390             var cb = ct + ch;
7391             var cr = cl + c.clientWidth;
7392
7393             if(t < ct){
7394                 c.scrollTop = t;
7395             }else if(b > cb){
7396                 c.scrollTop = b-ch;
7397             }
7398
7399             if(hscroll !== false){
7400                 if(l < cl){
7401                     c.scrollLeft = l;
7402                 }else if(r > cr){
7403                     c.scrollLeft = r-c.clientWidth;
7404                 }
7405             }
7406             return this;
7407         },
7408
7409         // private
7410         scrollChildIntoView : function(child, hscroll){
7411             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7412         },
7413
7414         /**
7415          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7416          * the new height may not be available immediately.
7417          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7418          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7419          * @param {Function} onComplete (optional) Function to call when animation completes
7420          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7421          * @return {Roo.Element} this
7422          */
7423         autoHeight : function(animate, duration, onComplete, easing){
7424             var oldHeight = this.getHeight();
7425             this.clip();
7426             this.setHeight(1); // force clipping
7427             setTimeout(function(){
7428                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7429                 if(!animate){
7430                     this.setHeight(height);
7431                     this.unclip();
7432                     if(typeof onComplete == "function"){
7433                         onComplete();
7434                     }
7435                 }else{
7436                     this.setHeight(oldHeight); // restore original height
7437                     this.setHeight(height, animate, duration, function(){
7438                         this.unclip();
7439                         if(typeof onComplete == "function") { onComplete(); }
7440                     }.createDelegate(this), easing);
7441                 }
7442             }.createDelegate(this), 0);
7443             return this;
7444         },
7445
7446         /**
7447          * Returns true if this element is an ancestor of the passed element
7448          * @param {HTMLElement/String} el The element to check
7449          * @return {Boolean} True if this element is an ancestor of el, else false
7450          */
7451         contains : function(el){
7452             if(!el){return false;}
7453             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7454         },
7455
7456         /**
7457          * Checks whether the element is currently visible using both visibility and display properties.
7458          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7459          * @return {Boolean} True if the element is currently visible, else false
7460          */
7461         isVisible : function(deep) {
7462             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7463             if(deep !== true || !vis){
7464                 return vis;
7465             }
7466             var p = this.dom.parentNode;
7467             while(p && p.tagName.toLowerCase() != "body"){
7468                 if(!Roo.fly(p, '_isVisible').isVisible()){
7469                     return false;
7470                 }
7471                 p = p.parentNode;
7472             }
7473             return true;
7474         },
7475
7476         /**
7477          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7478          * @param {String} selector The CSS selector
7479          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7480          * @return {CompositeElement/CompositeElementLite} The composite element
7481          */
7482         select : function(selector, unique){
7483             return El.select(selector, unique, this.dom);
7484         },
7485
7486         /**
7487          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7488          * @param {String} selector The CSS selector
7489          * @return {Array} An array of the matched nodes
7490          */
7491         query : function(selector, unique){
7492             return Roo.DomQuery.select(selector, this.dom);
7493         },
7494
7495         /**
7496          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7497          * @param {String} selector The CSS selector
7498          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7499          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7500          */
7501         child : function(selector, returnDom){
7502             var n = Roo.DomQuery.selectNode(selector, this.dom);
7503             return returnDom ? n : Roo.get(n);
7504         },
7505
7506         /**
7507          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7508          * @param {String} selector The CSS selector
7509          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7510          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7511          */
7512         down : function(selector, returnDom){
7513             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7514             return returnDom ? n : Roo.get(n);
7515         },
7516
7517         /**
7518          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7519          * @param {String} group The group the DD object is member of
7520          * @param {Object} config The DD config object
7521          * @param {Object} overrides An object containing methods to override/implement on the DD object
7522          * @return {Roo.dd.DD} The DD object
7523          */
7524         initDD : function(group, config, overrides){
7525             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7526             return Roo.apply(dd, overrides);
7527         },
7528
7529         /**
7530          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7531          * @param {String} group The group the DDProxy object is member of
7532          * @param {Object} config The DDProxy config object
7533          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7534          * @return {Roo.dd.DDProxy} The DDProxy object
7535          */
7536         initDDProxy : function(group, config, overrides){
7537             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7538             return Roo.apply(dd, overrides);
7539         },
7540
7541         /**
7542          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7543          * @param {String} group The group the DDTarget object is member of
7544          * @param {Object} config The DDTarget config object
7545          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7546          * @return {Roo.dd.DDTarget} The DDTarget object
7547          */
7548         initDDTarget : function(group, config, overrides){
7549             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7550             return Roo.apply(dd, overrides);
7551         },
7552
7553         /**
7554          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7555          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7556          * @param {Boolean} visible Whether the element is visible
7557          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7558          * @return {Roo.Element} this
7559          */
7560          setVisible : function(visible, animate){
7561             if(!animate || !A){
7562                 if(this.visibilityMode == El.DISPLAY){
7563                     this.setDisplayed(visible);
7564                 }else{
7565                     this.fixDisplay();
7566                     this.dom.style.visibility = visible ? "visible" : "hidden";
7567                 }
7568             }else{
7569                 // closure for composites
7570                 var dom = this.dom;
7571                 var visMode = this.visibilityMode;
7572                 if(visible){
7573                     this.setOpacity(.01);
7574                     this.setVisible(true);
7575                 }
7576                 this.anim({opacity: { to: (visible?1:0) }},
7577                       this.preanim(arguments, 1),
7578                       null, .35, 'easeIn', function(){
7579                          if(!visible){
7580                              if(visMode == El.DISPLAY){
7581                                  dom.style.display = "none";
7582                              }else{
7583                                  dom.style.visibility = "hidden";
7584                              }
7585                              Roo.get(dom).setOpacity(1);
7586                          }
7587                      });
7588             }
7589             return this;
7590         },
7591
7592         /**
7593          * Returns true if display is not "none"
7594          * @return {Boolean}
7595          */
7596         isDisplayed : function() {
7597             return this.getStyle("display") != "none";
7598         },
7599
7600         /**
7601          * Toggles the element's visibility or display, depending on visibility mode.
7602          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7603          * @return {Roo.Element} this
7604          */
7605         toggle : function(animate){
7606             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7607             return this;
7608         },
7609
7610         /**
7611          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7612          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7613          * @return {Roo.Element} this
7614          */
7615         setDisplayed : function(value) {
7616             if(typeof value == "boolean"){
7617                value = value ? this.originalDisplay : "none";
7618             }
7619             this.setStyle("display", value);
7620             return this;
7621         },
7622
7623         /**
7624          * Tries to focus the element. Any exceptions are caught and ignored.
7625          * @return {Roo.Element} this
7626          */
7627         focus : function() {
7628             try{
7629                 this.dom.focus();
7630             }catch(e){}
7631             return this;
7632         },
7633
7634         /**
7635          * Tries to blur the element. Any exceptions are caught and ignored.
7636          * @return {Roo.Element} this
7637          */
7638         blur : function() {
7639             try{
7640                 this.dom.blur();
7641             }catch(e){}
7642             return this;
7643         },
7644
7645         /**
7646          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7647          * @param {String/Array} className The CSS class to add, or an array of classes
7648          * @return {Roo.Element} this
7649          */
7650         addClass : function(className){
7651             if(className instanceof Array){
7652                 for(var i = 0, len = className.length; i < len; i++) {
7653                     this.addClass(className[i]);
7654                 }
7655             }else{
7656                 if(className && !this.hasClass(className)){
7657                     this.dom.className = this.dom.className + " " + className;
7658                 }
7659             }
7660             return this;
7661         },
7662
7663         /**
7664          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7665          * @param {String/Array} className The CSS class to add, or an array of classes
7666          * @return {Roo.Element} this
7667          */
7668         radioClass : function(className){
7669             var siblings = this.dom.parentNode.childNodes;
7670             for(var i = 0; i < siblings.length; i++) {
7671                 var s = siblings[i];
7672                 if(s.nodeType == 1){
7673                     Roo.get(s).removeClass(className);
7674                 }
7675             }
7676             this.addClass(className);
7677             return this;
7678         },
7679
7680         /**
7681          * Removes one or more CSS classes from the element.
7682          * @param {String/Array} className The CSS class to remove, or an array of classes
7683          * @return {Roo.Element} this
7684          */
7685         removeClass : function(className){
7686             if(!className || !this.dom.className){
7687                 return this;
7688             }
7689             if(className instanceof Array){
7690                 for(var i = 0, len = className.length; i < len; i++) {
7691                     this.removeClass(className[i]);
7692                 }
7693             }else{
7694                 if(this.hasClass(className)){
7695                     var re = this.classReCache[className];
7696                     if (!re) {
7697                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7698                        this.classReCache[className] = re;
7699                     }
7700                     this.dom.className =
7701                         this.dom.className.replace(re, " ");
7702                 }
7703             }
7704             return this;
7705         },
7706
7707         // private
7708         classReCache: {},
7709
7710         /**
7711          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7712          * @param {String} className The CSS class to toggle
7713          * @return {Roo.Element} this
7714          */
7715         toggleClass : function(className){
7716             if(this.hasClass(className)){
7717                 this.removeClass(className);
7718             }else{
7719                 this.addClass(className);
7720             }
7721             return this;
7722         },
7723
7724         /**
7725          * Checks if the specified CSS class exists on this element's DOM node.
7726          * @param {String} className The CSS class to check for
7727          * @return {Boolean} True if the class exists, else false
7728          */
7729         hasClass : function(className){
7730             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7731         },
7732
7733         /**
7734          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7735          * @param {String} oldClassName The CSS class to replace
7736          * @param {String} newClassName The replacement CSS class
7737          * @return {Roo.Element} this
7738          */
7739         replaceClass : function(oldClassName, newClassName){
7740             this.removeClass(oldClassName);
7741             this.addClass(newClassName);
7742             return this;
7743         },
7744
7745         /**
7746          * Returns an object with properties matching the styles requested.
7747          * For example, el.getStyles('color', 'font-size', 'width') might return
7748          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7749          * @param {String} style1 A style name
7750          * @param {String} style2 A style name
7751          * @param {String} etc.
7752          * @return {Object} The style object
7753          */
7754         getStyles : function(){
7755             var a = arguments, len = a.length, r = {};
7756             for(var i = 0; i < len; i++){
7757                 r[a[i]] = this.getStyle(a[i]);
7758             }
7759             return r;
7760         },
7761
7762         /**
7763          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7764          * @param {String} property The style property whose value is returned.
7765          * @return {String} The current value of the style property for this element.
7766          */
7767         getStyle : function(){
7768             return view && view.getComputedStyle ?
7769                 function(prop){
7770                     var el = this.dom, v, cs, camel;
7771                     if(prop == 'float'){
7772                         prop = "cssFloat";
7773                     }
7774                     if(el.style && (v = el.style[prop])){
7775                         return v;
7776                     }
7777                     if(cs = view.getComputedStyle(el, "")){
7778                         if(!(camel = propCache[prop])){
7779                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7780                         }
7781                         return cs[camel];
7782                     }
7783                     return null;
7784                 } :
7785                 function(prop){
7786                     var el = this.dom, v, cs, camel;
7787                     if(prop == 'opacity'){
7788                         if(typeof el.style.filter == 'string'){
7789                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7790                             if(m){
7791                                 var fv = parseFloat(m[1]);
7792                                 if(!isNaN(fv)){
7793                                     return fv ? fv / 100 : 0;
7794                                 }
7795                             }
7796                         }
7797                         return 1;
7798                     }else if(prop == 'float'){
7799                         prop = "styleFloat";
7800                     }
7801                     if(!(camel = propCache[prop])){
7802                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7803                     }
7804                     if(v = el.style[camel]){
7805                         return v;
7806                     }
7807                     if(cs = el.currentStyle){
7808                         return cs[camel];
7809                     }
7810                     return null;
7811                 };
7812         }(),
7813
7814         /**
7815          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7816          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7817          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7818          * @return {Roo.Element} this
7819          */
7820         setStyle : function(prop, value){
7821             if(typeof prop == "string"){
7822                 
7823                 if (prop == 'float') {
7824                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7825                     return this;
7826                 }
7827                 
7828                 var camel;
7829                 if(!(camel = propCache[prop])){
7830                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7831                 }
7832                 
7833                 if(camel == 'opacity') {
7834                     this.setOpacity(value);
7835                 }else{
7836                     this.dom.style[camel] = value;
7837                 }
7838             }else{
7839                 for(var style in prop){
7840                     if(typeof prop[style] != "function"){
7841                        this.setStyle(style, prop[style]);
7842                     }
7843                 }
7844             }
7845             return this;
7846         },
7847
7848         /**
7849          * More flexible version of {@link #setStyle} for setting style properties.
7850          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7851          * a function which returns such a specification.
7852          * @return {Roo.Element} this
7853          */
7854         applyStyles : function(style){
7855             Roo.DomHelper.applyStyles(this.dom, style);
7856             return this;
7857         },
7858
7859         /**
7860           * 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).
7861           * @return {Number} The X position of the element
7862           */
7863         getX : function(){
7864             return D.getX(this.dom);
7865         },
7866
7867         /**
7868           * 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).
7869           * @return {Number} The Y position of the element
7870           */
7871         getY : function(){
7872             return D.getY(this.dom);
7873         },
7874
7875         /**
7876           * 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).
7877           * @return {Array} The XY position of the element
7878           */
7879         getXY : function(){
7880             return D.getXY(this.dom);
7881         },
7882
7883         /**
7884          * 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).
7885          * @param {Number} The X position of the element
7886          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7887          * @return {Roo.Element} this
7888          */
7889         setX : function(x, animate){
7890             if(!animate || !A){
7891                 D.setX(this.dom, x);
7892             }else{
7893                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7894             }
7895             return this;
7896         },
7897
7898         /**
7899          * 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).
7900          * @param {Number} The Y position of the element
7901          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7902          * @return {Roo.Element} this
7903          */
7904         setY : function(y, animate){
7905             if(!animate || !A){
7906                 D.setY(this.dom, y);
7907             }else{
7908                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7909             }
7910             return this;
7911         },
7912
7913         /**
7914          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7915          * @param {String} left The left CSS property value
7916          * @return {Roo.Element} this
7917          */
7918         setLeft : function(left){
7919             this.setStyle("left", this.addUnits(left));
7920             return this;
7921         },
7922
7923         /**
7924          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7925          * @param {String} top The top CSS property value
7926          * @return {Roo.Element} this
7927          */
7928         setTop : function(top){
7929             this.setStyle("top", this.addUnits(top));
7930             return this;
7931         },
7932
7933         /**
7934          * Sets the element's CSS right style.
7935          * @param {String} right The right CSS property value
7936          * @return {Roo.Element} this
7937          */
7938         setRight : function(right){
7939             this.setStyle("right", this.addUnits(right));
7940             return this;
7941         },
7942
7943         /**
7944          * Sets the element's CSS bottom style.
7945          * @param {String} bottom The bottom CSS property value
7946          * @return {Roo.Element} this
7947          */
7948         setBottom : function(bottom){
7949             this.setStyle("bottom", this.addUnits(bottom));
7950             return this;
7951         },
7952
7953         /**
7954          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7955          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7956          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7957          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7958          * @return {Roo.Element} this
7959          */
7960         setXY : function(pos, animate){
7961             if(!animate || !A){
7962                 D.setXY(this.dom, pos);
7963             }else{
7964                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7965             }
7966             return this;
7967         },
7968
7969         /**
7970          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7971          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7972          * @param {Number} x X value for new position (coordinates are page-based)
7973          * @param {Number} y Y value for new position (coordinates are page-based)
7974          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7975          * @return {Roo.Element} this
7976          */
7977         setLocation : function(x, y, animate){
7978             this.setXY([x, y], this.preanim(arguments, 2));
7979             return this;
7980         },
7981
7982         /**
7983          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7984          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7985          * @param {Number} x X value for new position (coordinates are page-based)
7986          * @param {Number} y Y value for new position (coordinates are page-based)
7987          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7988          * @return {Roo.Element} this
7989          */
7990         moveTo : function(x, y, animate){
7991             this.setXY([x, y], this.preanim(arguments, 2));
7992             return this;
7993         },
7994
7995         /**
7996          * Returns the region of the given element.
7997          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7998          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7999          */
8000         getRegion : function(){
8001             return D.getRegion(this.dom);
8002         },
8003
8004         /**
8005          * Returns the offset height of the element
8006          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8007          * @return {Number} The element's height
8008          */
8009         getHeight : function(contentHeight){
8010             var h = this.dom.offsetHeight || 0;
8011             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8012         },
8013
8014         /**
8015          * Returns the offset width of the element
8016          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8017          * @return {Number} The element's width
8018          */
8019         getWidth : function(contentWidth){
8020             var w = this.dom.offsetWidth || 0;
8021             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8022         },
8023
8024         /**
8025          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8026          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8027          * if a height has not been set using CSS.
8028          * @return {Number}
8029          */
8030         getComputedHeight : function(){
8031             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8032             if(!h){
8033                 h = parseInt(this.getStyle('height'), 10) || 0;
8034                 if(!this.isBorderBox()){
8035                     h += this.getFrameWidth('tb');
8036                 }
8037             }
8038             return h;
8039         },
8040
8041         /**
8042          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8043          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8044          * if a width has not been set using CSS.
8045          * @return {Number}
8046          */
8047         getComputedWidth : function(){
8048             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8049             if(!w){
8050                 w = parseInt(this.getStyle('width'), 10) || 0;
8051                 if(!this.isBorderBox()){
8052                     w += this.getFrameWidth('lr');
8053                 }
8054             }
8055             return w;
8056         },
8057
8058         /**
8059          * Returns the size of the element.
8060          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8061          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8062          */
8063         getSize : function(contentSize){
8064             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8065         },
8066
8067         /**
8068          * Returns the width and height of the viewport.
8069          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8070          */
8071         getViewSize : function(){
8072             var d = this.dom, doc = document, aw = 0, ah = 0;
8073             if(d == doc || d == doc.body){
8074                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8075             }else{
8076                 return {
8077                     width : d.clientWidth,
8078                     height: d.clientHeight
8079                 };
8080             }
8081         },
8082
8083         /**
8084          * Returns the value of the "value" attribute
8085          * @param {Boolean} asNumber true to parse the value as a number
8086          * @return {String/Number}
8087          */
8088         getValue : function(asNumber){
8089             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8090         },
8091
8092         // private
8093         adjustWidth : function(width){
8094             if(typeof width == "number"){
8095                 if(this.autoBoxAdjust && !this.isBorderBox()){
8096                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8097                 }
8098                 if(width < 0){
8099                     width = 0;
8100                 }
8101             }
8102             return width;
8103         },
8104
8105         // private
8106         adjustHeight : function(height){
8107             if(typeof height == "number"){
8108                if(this.autoBoxAdjust && !this.isBorderBox()){
8109                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8110                }
8111                if(height < 0){
8112                    height = 0;
8113                }
8114             }
8115             return height;
8116         },
8117
8118         /**
8119          * Set the width of the element
8120          * @param {Number} width The new width
8121          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8122          * @return {Roo.Element} this
8123          */
8124         setWidth : function(width, animate){
8125             width = this.adjustWidth(width);
8126             if(!animate || !A){
8127                 this.dom.style.width = this.addUnits(width);
8128             }else{
8129                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8130             }
8131             return this;
8132         },
8133
8134         /**
8135          * Set the height of the element
8136          * @param {Number} height The new height
8137          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8138          * @return {Roo.Element} this
8139          */
8140          setHeight : function(height, animate){
8141             height = this.adjustHeight(height);
8142             if(!animate || !A){
8143                 this.dom.style.height = this.addUnits(height);
8144             }else{
8145                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8146             }
8147             return this;
8148         },
8149
8150         /**
8151          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8152          * @param {Number} width The new width
8153          * @param {Number} height The new height
8154          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8155          * @return {Roo.Element} this
8156          */
8157          setSize : function(width, height, animate){
8158             if(typeof width == "object"){ // in case of object from getSize()
8159                 height = width.height; width = width.width;
8160             }
8161             width = this.adjustWidth(width); height = this.adjustHeight(height);
8162             if(!animate || !A){
8163                 this.dom.style.width = this.addUnits(width);
8164                 this.dom.style.height = this.addUnits(height);
8165             }else{
8166                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8167             }
8168             return this;
8169         },
8170
8171         /**
8172          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8173          * @param {Number} x X value for new position (coordinates are page-based)
8174          * @param {Number} y Y value for new position (coordinates are page-based)
8175          * @param {Number} width The new width
8176          * @param {Number} height The new height
8177          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8178          * @return {Roo.Element} this
8179          */
8180         setBounds : function(x, y, width, height, animate){
8181             if(!animate || !A){
8182                 this.setSize(width, height);
8183                 this.setLocation(x, y);
8184             }else{
8185                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8186                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8187                               this.preanim(arguments, 4), 'motion');
8188             }
8189             return this;
8190         },
8191
8192         /**
8193          * 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.
8194          * @param {Roo.lib.Region} region The region to fill
8195          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8196          * @return {Roo.Element} this
8197          */
8198         setRegion : function(region, animate){
8199             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8200             return this;
8201         },
8202
8203         /**
8204          * Appends an event handler
8205          *
8206          * @param {String}   eventName     The type of event to append
8207          * @param {Function} fn        The method the event invokes
8208          * @param {Object} scope       (optional) The scope (this object) of the fn
8209          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8210          */
8211         addListener : function(eventName, fn, scope, options){
8212             if (this.dom) {
8213                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8214             }
8215         },
8216
8217         /**
8218          * Removes an event handler from this element
8219          * @param {String} eventName the type of event to remove
8220          * @param {Function} fn the method the event invokes
8221          * @return {Roo.Element} this
8222          */
8223         removeListener : function(eventName, fn){
8224             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8225             return this;
8226         },
8227
8228         /**
8229          * Removes all previous added listeners from this element
8230          * @return {Roo.Element} this
8231          */
8232         removeAllListeners : function(){
8233             E.purgeElement(this.dom);
8234             return this;
8235         },
8236
8237         relayEvent : function(eventName, observable){
8238             this.on(eventName, function(e){
8239                 observable.fireEvent(eventName, e);
8240             });
8241         },
8242
8243         /**
8244          * Set the opacity of the element
8245          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8246          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8247          * @return {Roo.Element} this
8248          */
8249          setOpacity : function(opacity, animate){
8250             if(!animate || !A){
8251                 var s = this.dom.style;
8252                 if(Roo.isIE){
8253                     s.zoom = 1;
8254                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8255                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8256                 }else{
8257                     s.opacity = opacity;
8258                 }
8259             }else{
8260                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8261             }
8262             return this;
8263         },
8264
8265         /**
8266          * Gets the left X coordinate
8267          * @param {Boolean} local True to get the local css position instead of page coordinate
8268          * @return {Number}
8269          */
8270         getLeft : function(local){
8271             if(!local){
8272                 return this.getX();
8273             }else{
8274                 return parseInt(this.getStyle("left"), 10) || 0;
8275             }
8276         },
8277
8278         /**
8279          * Gets the right X coordinate of the element (element X position + element width)
8280          * @param {Boolean} local True to get the local css position instead of page coordinate
8281          * @return {Number}
8282          */
8283         getRight : function(local){
8284             if(!local){
8285                 return this.getX() + this.getWidth();
8286             }else{
8287                 return (this.getLeft(true) + this.getWidth()) || 0;
8288             }
8289         },
8290
8291         /**
8292          * Gets the top Y coordinate
8293          * @param {Boolean} local True to get the local css position instead of page coordinate
8294          * @return {Number}
8295          */
8296         getTop : function(local) {
8297             if(!local){
8298                 return this.getY();
8299             }else{
8300                 return parseInt(this.getStyle("top"), 10) || 0;
8301             }
8302         },
8303
8304         /**
8305          * Gets the bottom Y coordinate of the element (element Y position + element height)
8306          * @param {Boolean} local True to get the local css position instead of page coordinate
8307          * @return {Number}
8308          */
8309         getBottom : function(local){
8310             if(!local){
8311                 return this.getY() + this.getHeight();
8312             }else{
8313                 return (this.getTop(true) + this.getHeight()) || 0;
8314             }
8315         },
8316
8317         /**
8318         * Initializes positioning on this element. If a desired position is not passed, it will make the
8319         * the element positioned relative IF it is not already positioned.
8320         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8321         * @param {Number} zIndex (optional) The zIndex to apply
8322         * @param {Number} x (optional) Set the page X position
8323         * @param {Number} y (optional) Set the page Y position
8324         */
8325         position : function(pos, zIndex, x, y){
8326             if(!pos){
8327                if(this.getStyle('position') == 'static'){
8328                    this.setStyle('position', 'relative');
8329                }
8330             }else{
8331                 this.setStyle("position", pos);
8332             }
8333             if(zIndex){
8334                 this.setStyle("z-index", zIndex);
8335             }
8336             if(x !== undefined && y !== undefined){
8337                 this.setXY([x, y]);
8338             }else if(x !== undefined){
8339                 this.setX(x);
8340             }else if(y !== undefined){
8341                 this.setY(y);
8342             }
8343         },
8344
8345         /**
8346         * Clear positioning back to the default when the document was loaded
8347         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8348         * @return {Roo.Element} this
8349          */
8350         clearPositioning : function(value){
8351             value = value ||'';
8352             this.setStyle({
8353                 "left": value,
8354                 "right": value,
8355                 "top": value,
8356                 "bottom": value,
8357                 "z-index": "",
8358                 "position" : "static"
8359             });
8360             return this;
8361         },
8362
8363         /**
8364         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8365         * snapshot before performing an update and then restoring the element.
8366         * @return {Object}
8367         */
8368         getPositioning : function(){
8369             var l = this.getStyle("left");
8370             var t = this.getStyle("top");
8371             return {
8372                 "position" : this.getStyle("position"),
8373                 "left" : l,
8374                 "right" : l ? "" : this.getStyle("right"),
8375                 "top" : t,
8376                 "bottom" : t ? "" : this.getStyle("bottom"),
8377                 "z-index" : this.getStyle("z-index")
8378             };
8379         },
8380
8381         /**
8382          * Gets the width of the border(s) for the specified side(s)
8383          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8384          * passing lr would get the border (l)eft width + the border (r)ight width.
8385          * @return {Number} The width of the sides passed added together
8386          */
8387         getBorderWidth : function(side){
8388             return this.addStyles(side, El.borders);
8389         },
8390
8391         /**
8392          * Gets the width of the padding(s) for the specified side(s)
8393          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8394          * passing lr would get the padding (l)eft + the padding (r)ight.
8395          * @return {Number} The padding of the sides passed added together
8396          */
8397         getPadding : function(side){
8398             return this.addStyles(side, El.paddings);
8399         },
8400
8401         /**
8402         * Set positioning with an object returned by getPositioning().
8403         * @param {Object} posCfg
8404         * @return {Roo.Element} this
8405          */
8406         setPositioning : function(pc){
8407             this.applyStyles(pc);
8408             if(pc.right == "auto"){
8409                 this.dom.style.right = "";
8410             }
8411             if(pc.bottom == "auto"){
8412                 this.dom.style.bottom = "";
8413             }
8414             return this;
8415         },
8416
8417         // private
8418         fixDisplay : function(){
8419             if(this.getStyle("display") == "none"){
8420                 this.setStyle("visibility", "hidden");
8421                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8422                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8423                     this.setStyle("display", "block");
8424                 }
8425             }
8426         },
8427
8428         /**
8429          * Quick set left and top adding default units
8430          * @param {String} left The left CSS property value
8431          * @param {String} top The top CSS property value
8432          * @return {Roo.Element} this
8433          */
8434          setLeftTop : function(left, top){
8435             this.dom.style.left = this.addUnits(left);
8436             this.dom.style.top = this.addUnits(top);
8437             return this;
8438         },
8439
8440         /**
8441          * Move this element relative to its current position.
8442          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8443          * @param {Number} distance How far to move the element in pixels
8444          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8445          * @return {Roo.Element} this
8446          */
8447          move : function(direction, distance, animate){
8448             var xy = this.getXY();
8449             direction = direction.toLowerCase();
8450             switch(direction){
8451                 case "l":
8452                 case "left":
8453                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8454                     break;
8455                case "r":
8456                case "right":
8457                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8458                     break;
8459                case "t":
8460                case "top":
8461                case "up":
8462                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8463                     break;
8464                case "b":
8465                case "bottom":
8466                case "down":
8467                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8468                     break;
8469             }
8470             return this;
8471         },
8472
8473         /**
8474          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8475          * @return {Roo.Element} this
8476          */
8477         clip : function(){
8478             if(!this.isClipped){
8479                this.isClipped = true;
8480                this.originalClip = {
8481                    "o": this.getStyle("overflow"),
8482                    "x": this.getStyle("overflow-x"),
8483                    "y": this.getStyle("overflow-y")
8484                };
8485                this.setStyle("overflow", "hidden");
8486                this.setStyle("overflow-x", "hidden");
8487                this.setStyle("overflow-y", "hidden");
8488             }
8489             return this;
8490         },
8491
8492         /**
8493          *  Return clipping (overflow) to original clipping before clip() was called
8494          * @return {Roo.Element} this
8495          */
8496         unclip : function(){
8497             if(this.isClipped){
8498                 this.isClipped = false;
8499                 var o = this.originalClip;
8500                 if(o.o){this.setStyle("overflow", o.o);}
8501                 if(o.x){this.setStyle("overflow-x", o.x);}
8502                 if(o.y){this.setStyle("overflow-y", o.y);}
8503             }
8504             return this;
8505         },
8506
8507
8508         /**
8509          * Gets the x,y coordinates specified by the anchor position on the element.
8510          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8511          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8512          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8513          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8514          * @return {Array} [x, y] An array containing the element's x and y coordinates
8515          */
8516         getAnchorXY : function(anchor, local, s){
8517             //Passing a different size is useful for pre-calculating anchors,
8518             //especially for anchored animations that change the el size.
8519
8520             var w, h, vp = false;
8521             if(!s){
8522                 var d = this.dom;
8523                 if(d == document.body || d == document){
8524                     vp = true;
8525                     w = D.getViewWidth(); h = D.getViewHeight();
8526                 }else{
8527                     w = this.getWidth(); h = this.getHeight();
8528                 }
8529             }else{
8530                 w = s.width;  h = s.height;
8531             }
8532             var x = 0, y = 0, r = Math.round;
8533             switch((anchor || "tl").toLowerCase()){
8534                 case "c":
8535                     x = r(w*.5);
8536                     y = r(h*.5);
8537                 break;
8538                 case "t":
8539                     x = r(w*.5);
8540                     y = 0;
8541                 break;
8542                 case "l":
8543                     x = 0;
8544                     y = r(h*.5);
8545                 break;
8546                 case "r":
8547                     x = w;
8548                     y = r(h*.5);
8549                 break;
8550                 case "b":
8551                     x = r(w*.5);
8552                     y = h;
8553                 break;
8554                 case "tl":
8555                     x = 0;
8556                     y = 0;
8557                 break;
8558                 case "bl":
8559                     x = 0;
8560                     y = h;
8561                 break;
8562                 case "br":
8563                     x = w;
8564                     y = h;
8565                 break;
8566                 case "tr":
8567                     x = w;
8568                     y = 0;
8569                 break;
8570             }
8571             if(local === true){
8572                 return [x, y];
8573             }
8574             if(vp){
8575                 var sc = this.getScroll();
8576                 return [x + sc.left, y + sc.top];
8577             }
8578             //Add the element's offset xy
8579             var o = this.getXY();
8580             return [x+o[0], y+o[1]];
8581         },
8582
8583         /**
8584          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8585          * supported position values.
8586          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8587          * @param {String} position The position to align to.
8588          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8589          * @return {Array} [x, y]
8590          */
8591         getAlignToXY : function(el, p, o)
8592         {
8593             el = Roo.get(el);
8594             var d = this.dom;
8595             if(!el.dom){
8596                 throw "Element.alignTo with an element that doesn't exist";
8597             }
8598             var c = false; //constrain to viewport
8599             var p1 = "", p2 = "";
8600             o = o || [0,0];
8601
8602             if(!p){
8603                 p = "tl-bl";
8604             }else if(p == "?"){
8605                 p = "tl-bl?";
8606             }else if(p.indexOf("-") == -1){
8607                 p = "tl-" + p;
8608             }
8609             p = p.toLowerCase();
8610             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8611             if(!m){
8612                throw "Element.alignTo with an invalid alignment " + p;
8613             }
8614             p1 = m[1]; p2 = m[2]; c = !!m[3];
8615
8616             //Subtract the aligned el's internal xy from the target's offset xy
8617             //plus custom offset to get the aligned el's new offset xy
8618             var a1 = this.getAnchorXY(p1, true);
8619             var a2 = el.getAnchorXY(p2, false);
8620             var x = a2[0] - a1[0] + o[0];
8621             var y = a2[1] - a1[1] + o[1];
8622             if(c){
8623                 //constrain the aligned el to viewport if necessary
8624                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8625                 // 5px of margin for ie
8626                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8627
8628                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8629                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8630                 //otherwise swap the aligned el to the opposite border of the target.
8631                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8632                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8633                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
8634                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8635
8636                var doc = document;
8637                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8638                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8639
8640                if((x+w) > dw + scrollX){
8641                     x = swapX ? r.left-w : dw+scrollX-w;
8642                 }
8643                if(x < scrollX){
8644                    x = swapX ? r.right : scrollX;
8645                }
8646                if((y+h) > dh + scrollY){
8647                     y = swapY ? r.top-h : dh+scrollY-h;
8648                 }
8649                if (y < scrollY){
8650                    y = swapY ? r.bottom : scrollY;
8651                }
8652             }
8653             return [x,y];
8654         },
8655
8656         // private
8657         getConstrainToXY : function(){
8658             var os = {top:0, left:0, bottom:0, right: 0};
8659
8660             return function(el, local, offsets, proposedXY){
8661                 el = Roo.get(el);
8662                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8663
8664                 var vw, vh, vx = 0, vy = 0;
8665                 if(el.dom == document.body || el.dom == document){
8666                     vw = Roo.lib.Dom.getViewWidth();
8667                     vh = Roo.lib.Dom.getViewHeight();
8668                 }else{
8669                     vw = el.dom.clientWidth;
8670                     vh = el.dom.clientHeight;
8671                     if(!local){
8672                         var vxy = el.getXY();
8673                         vx = vxy[0];
8674                         vy = vxy[1];
8675                     }
8676                 }
8677
8678                 var s = el.getScroll();
8679
8680                 vx += offsets.left + s.left;
8681                 vy += offsets.top + s.top;
8682
8683                 vw -= offsets.right;
8684                 vh -= offsets.bottom;
8685
8686                 var vr = vx+vw;
8687                 var vb = vy+vh;
8688
8689                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8690                 var x = xy[0], y = xy[1];
8691                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8692
8693                 // only move it if it needs it
8694                 var moved = false;
8695
8696                 // first validate right/bottom
8697                 if((x + w) > vr){
8698                     x = vr - w;
8699                     moved = true;
8700                 }
8701                 if((y + h) > vb){
8702                     y = vb - h;
8703                     moved = true;
8704                 }
8705                 // then make sure top/left isn't negative
8706                 if(x < vx){
8707                     x = vx;
8708                     moved = true;
8709                 }
8710                 if(y < vy){
8711                     y = vy;
8712                     moved = true;
8713                 }
8714                 return moved ? [x, y] : false;
8715             };
8716         }(),
8717
8718         // private
8719         adjustForConstraints : function(xy, parent, offsets){
8720             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8721         },
8722
8723         /**
8724          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8725          * document it aligns it to the viewport.
8726          * The position parameter is optional, and can be specified in any one of the following formats:
8727          * <ul>
8728          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8729          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8730          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8731          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8732          *   <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
8733          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8734          * </ul>
8735          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8736          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8737          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8738          * that specified in order to enforce the viewport constraints.
8739          * Following are all of the supported anchor positions:
8740     <pre>
8741     Value  Description
8742     -----  -----------------------------
8743     tl     The top left corner (default)
8744     t      The center of the top edge
8745     tr     The top right corner
8746     l      The center of the left edge
8747     c      In the center of the element
8748     r      The center of the right edge
8749     bl     The bottom left corner
8750     b      The center of the bottom edge
8751     br     The bottom right corner
8752     </pre>
8753     Example Usage:
8754     <pre><code>
8755     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8756     el.alignTo("other-el");
8757
8758     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8759     el.alignTo("other-el", "tr?");
8760
8761     // align the bottom right corner of el with the center left edge of other-el
8762     el.alignTo("other-el", "br-l?");
8763
8764     // align the center of el with the bottom left corner of other-el and
8765     // adjust the x position by -6 pixels (and the y position by 0)
8766     el.alignTo("other-el", "c-bl", [-6, 0]);
8767     </code></pre>
8768          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8769          * @param {String} position The position to align to.
8770          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8771          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8772          * @return {Roo.Element} this
8773          */
8774         alignTo : function(element, position, offsets, animate){
8775             var xy = this.getAlignToXY(element, position, offsets);
8776             this.setXY(xy, this.preanim(arguments, 3));
8777             return this;
8778         },
8779
8780         /**
8781          * Anchors an element to another element and realigns it when the window is resized.
8782          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8783          * @param {String} position The position to align to.
8784          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8785          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8786          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8787          * is a number, it is used as the buffer delay (defaults to 50ms).
8788          * @param {Function} callback The function to call after the animation finishes
8789          * @return {Roo.Element} this
8790          */
8791         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8792             var action = function(){
8793                 this.alignTo(el, alignment, offsets, animate);
8794                 Roo.callback(callback, this);
8795             };
8796             Roo.EventManager.onWindowResize(action, this);
8797             var tm = typeof monitorScroll;
8798             if(tm != 'undefined'){
8799                 Roo.EventManager.on(window, 'scroll', action, this,
8800                     {buffer: tm == 'number' ? monitorScroll : 50});
8801             }
8802             action.call(this); // align immediately
8803             return this;
8804         },
8805         /**
8806          * Clears any opacity settings from this element. Required in some cases for IE.
8807          * @return {Roo.Element} this
8808          */
8809         clearOpacity : function(){
8810             if (window.ActiveXObject) {
8811                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8812                     this.dom.style.filter = "";
8813                 }
8814             } else {
8815                 this.dom.style.opacity = "";
8816                 this.dom.style["-moz-opacity"] = "";
8817                 this.dom.style["-khtml-opacity"] = "";
8818             }
8819             return this;
8820         },
8821
8822         /**
8823          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8824          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8825          * @return {Roo.Element} this
8826          */
8827         hide : function(animate){
8828             this.setVisible(false, this.preanim(arguments, 0));
8829             return this;
8830         },
8831
8832         /**
8833         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8834         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8835          * @return {Roo.Element} this
8836          */
8837         show : function(animate){
8838             this.setVisible(true, this.preanim(arguments, 0));
8839             return this;
8840         },
8841
8842         /**
8843          * @private Test if size has a unit, otherwise appends the default
8844          */
8845         addUnits : function(size){
8846             return Roo.Element.addUnits(size, this.defaultUnit);
8847         },
8848
8849         /**
8850          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8851          * @return {Roo.Element} this
8852          */
8853         beginMeasure : function(){
8854             var el = this.dom;
8855             if(el.offsetWidth || el.offsetHeight){
8856                 return this; // offsets work already
8857             }
8858             var changed = [];
8859             var p = this.dom, b = document.body; // start with this element
8860             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8861                 var pe = Roo.get(p);
8862                 if(pe.getStyle('display') == 'none'){
8863                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8864                     p.style.visibility = "hidden";
8865                     p.style.display = "block";
8866                 }
8867                 p = p.parentNode;
8868             }
8869             this._measureChanged = changed;
8870             return this;
8871
8872         },
8873
8874         /**
8875          * Restores displays to before beginMeasure was called
8876          * @return {Roo.Element} this
8877          */
8878         endMeasure : function(){
8879             var changed = this._measureChanged;
8880             if(changed){
8881                 for(var i = 0, len = changed.length; i < len; i++) {
8882                     var r = changed[i];
8883                     r.el.style.visibility = r.visibility;
8884                     r.el.style.display = "none";
8885                 }
8886                 this._measureChanged = null;
8887             }
8888             return this;
8889         },
8890
8891         /**
8892         * Update the innerHTML of this element, optionally searching for and processing scripts
8893         * @param {String} html The new HTML
8894         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8895         * @param {Function} callback For async script loading you can be noticed when the update completes
8896         * @return {Roo.Element} this
8897          */
8898         update : function(html, loadScripts, callback){
8899             if(typeof html == "undefined"){
8900                 html = "";
8901             }
8902             if(loadScripts !== true){
8903                 this.dom.innerHTML = html;
8904                 if(typeof callback == "function"){
8905                     callback();
8906                 }
8907                 return this;
8908             }
8909             var id = Roo.id();
8910             var dom = this.dom;
8911
8912             html += '<span id="' + id + '"></span>';
8913
8914             E.onAvailable(id, function(){
8915                 var hd = document.getElementsByTagName("head")[0];
8916                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8917                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8918                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8919
8920                 var match;
8921                 while(match = re.exec(html)){
8922                     var attrs = match[1];
8923                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8924                     if(srcMatch && srcMatch[2]){
8925                        var s = document.createElement("script");
8926                        s.src = srcMatch[2];
8927                        var typeMatch = attrs.match(typeRe);
8928                        if(typeMatch && typeMatch[2]){
8929                            s.type = typeMatch[2];
8930                        }
8931                        hd.appendChild(s);
8932                     }else if(match[2] && match[2].length > 0){
8933                         if(window.execScript) {
8934                            window.execScript(match[2]);
8935                         } else {
8936                             /**
8937                              * eval:var:id
8938                              * eval:var:dom
8939                              * eval:var:html
8940                              * 
8941                              */
8942                            window.eval(match[2]);
8943                         }
8944                     }
8945                 }
8946                 var el = document.getElementById(id);
8947                 if(el){el.parentNode.removeChild(el);}
8948                 if(typeof callback == "function"){
8949                     callback();
8950                 }
8951             });
8952             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8953             return this;
8954         },
8955
8956         /**
8957          * Direct access to the UpdateManager update() method (takes the same parameters).
8958          * @param {String/Function} url The url for this request or a function to call to get the url
8959          * @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}
8960          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8961          * @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.
8962          * @return {Roo.Element} this
8963          */
8964         load : function(){
8965             var um = this.getUpdateManager();
8966             um.update.apply(um, arguments);
8967             return this;
8968         },
8969
8970         /**
8971         * Gets this element's UpdateManager
8972         * @return {Roo.UpdateManager} The UpdateManager
8973         */
8974         getUpdateManager : function(){
8975             if(!this.updateManager){
8976                 this.updateManager = new Roo.UpdateManager(this);
8977             }
8978             return this.updateManager;
8979         },
8980
8981         /**
8982          * Disables text selection for this element (normalized across browsers)
8983          * @return {Roo.Element} this
8984          */
8985         unselectable : function(){
8986             this.dom.unselectable = "on";
8987             this.swallowEvent("selectstart", true);
8988             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8989             this.addClass("x-unselectable");
8990             return this;
8991         },
8992
8993         /**
8994         * Calculates the x, y to center this element on the screen
8995         * @return {Array} The x, y values [x, y]
8996         */
8997         getCenterXY : function(){
8998             return this.getAlignToXY(document, 'c-c');
8999         },
9000
9001         /**
9002         * Centers the Element in either the viewport, or another Element.
9003         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9004         */
9005         center : function(centerIn){
9006             this.alignTo(centerIn || document, 'c-c');
9007             return this;
9008         },
9009
9010         /**
9011          * Tests various css rules/browsers to determine if this element uses a border box
9012          * @return {Boolean}
9013          */
9014         isBorderBox : function(){
9015             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9016         },
9017
9018         /**
9019          * Return a box {x, y, width, height} that can be used to set another elements
9020          * size/location to match this element.
9021          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9022          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9023          * @return {Object} box An object in the format {x, y, width, height}
9024          */
9025         getBox : function(contentBox, local){
9026             var xy;
9027             if(!local){
9028                 xy = this.getXY();
9029             }else{
9030                 var left = parseInt(this.getStyle("left"), 10) || 0;
9031                 var top = parseInt(this.getStyle("top"), 10) || 0;
9032                 xy = [left, top];
9033             }
9034             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9035             if(!contentBox){
9036                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9037             }else{
9038                 var l = this.getBorderWidth("l")+this.getPadding("l");
9039                 var r = this.getBorderWidth("r")+this.getPadding("r");
9040                 var t = this.getBorderWidth("t")+this.getPadding("t");
9041                 var b = this.getBorderWidth("b")+this.getPadding("b");
9042                 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)};
9043             }
9044             bx.right = bx.x + bx.width;
9045             bx.bottom = bx.y + bx.height;
9046             return bx;
9047         },
9048
9049         /**
9050          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9051          for more information about the sides.
9052          * @param {String} sides
9053          * @return {Number}
9054          */
9055         getFrameWidth : function(sides, onlyContentBox){
9056             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9057         },
9058
9059         /**
9060          * 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.
9061          * @param {Object} box The box to fill {x, y, width, height}
9062          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9063          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9064          * @return {Roo.Element} this
9065          */
9066         setBox : function(box, adjust, animate){
9067             var w = box.width, h = box.height;
9068             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9069                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9070                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9071             }
9072             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9073             return this;
9074         },
9075
9076         /**
9077          * Forces the browser to repaint this element
9078          * @return {Roo.Element} this
9079          */
9080          repaint : function(){
9081             var dom = this.dom;
9082             this.addClass("x-repaint");
9083             setTimeout(function(){
9084                 Roo.get(dom).removeClass("x-repaint");
9085             }, 1);
9086             return this;
9087         },
9088
9089         /**
9090          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9091          * then it returns the calculated width of the sides (see getPadding)
9092          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9093          * @return {Object/Number}
9094          */
9095         getMargins : function(side){
9096             if(!side){
9097                 return {
9098                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9099                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9100                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9101                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9102                 };
9103             }else{
9104                 return this.addStyles(side, El.margins);
9105              }
9106         },
9107
9108         // private
9109         addStyles : function(sides, styles){
9110             var val = 0, v, w;
9111             for(var i = 0, len = sides.length; i < len; i++){
9112                 v = this.getStyle(styles[sides.charAt(i)]);
9113                 if(v){
9114                      w = parseInt(v, 10);
9115                      if(w){ val += w; }
9116                 }
9117             }
9118             return val;
9119         },
9120
9121         /**
9122          * Creates a proxy element of this element
9123          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9124          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9125          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9126          * @return {Roo.Element} The new proxy element
9127          */
9128         createProxy : function(config, renderTo, matchBox){
9129             if(renderTo){
9130                 renderTo = Roo.getDom(renderTo);
9131             }else{
9132                 renderTo = document.body;
9133             }
9134             config = typeof config == "object" ?
9135                 config : {tag : "div", cls: config};
9136             var proxy = Roo.DomHelper.append(renderTo, config, true);
9137             if(matchBox){
9138                proxy.setBox(this.getBox());
9139             }
9140             return proxy;
9141         },
9142
9143         /**
9144          * Puts a mask over this element to disable user interaction. Requires core.css.
9145          * This method can only be applied to elements which accept child nodes.
9146          * @param {String} msg (optional) A message to display in the mask
9147          * @param {String} msgCls (optional) A css class to apply to the msg element
9148          * @return {Element} The mask  element
9149          */
9150         mask : function(msg, msgCls)
9151         {
9152             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9153                 this.setStyle("position", "relative");
9154             }
9155             if(!this._mask){
9156                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9157             }
9158             
9159             this.addClass("x-masked");
9160             this._mask.setDisplayed(true);
9161             
9162             // we wander
9163             var z = 0;
9164             var dom = this.dom;
9165             while (dom && dom.style) {
9166                 if (!isNaN(parseInt(dom.style.zIndex))) {
9167                     z = Math.max(z, parseInt(dom.style.zIndex));
9168                 }
9169                 dom = dom.parentNode;
9170             }
9171             // if we are masking the body - then it hides everything..
9172             if (this.dom == document.body) {
9173                 z = 1000000;
9174                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9175                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9176             }
9177            
9178             if(typeof msg == 'string'){
9179                 if(!this._maskMsg){
9180                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9181                         cls: "roo-el-mask-msg", 
9182                         cn: [
9183                             {
9184                                 tag: 'i',
9185                                 cls: 'fa fa-spinner fa-spin'
9186                             },
9187                             {
9188                                 tag: 'div'
9189                             }   
9190                         ]
9191                     }, true);
9192                 }
9193                 var mm = this._maskMsg;
9194                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9195                 if (mm.dom.lastChild) { // weird IE issue?
9196                     mm.dom.lastChild.innerHTML = msg;
9197                 }
9198                 mm.setDisplayed(true);
9199                 mm.center(this);
9200                 mm.setStyle('z-index', z + 102);
9201             }
9202             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9203                 this._mask.setHeight(this.getHeight());
9204             }
9205             this._mask.setStyle('z-index', z + 100);
9206             
9207             return this._mask;
9208         },
9209
9210         /**
9211          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9212          * it is cached for reuse.
9213          */
9214         unmask : function(removeEl){
9215             if(this._mask){
9216                 if(removeEl === true){
9217                     this._mask.remove();
9218                     delete this._mask;
9219                     if(this._maskMsg){
9220                         this._maskMsg.remove();
9221                         delete this._maskMsg;
9222                     }
9223                 }else{
9224                     this._mask.setDisplayed(false);
9225                     if(this._maskMsg){
9226                         this._maskMsg.setDisplayed(false);
9227                     }
9228                 }
9229             }
9230             this.removeClass("x-masked");
9231         },
9232
9233         /**
9234          * Returns true if this element is masked
9235          * @return {Boolean}
9236          */
9237         isMasked : function(){
9238             return this._mask && this._mask.isVisible();
9239         },
9240
9241         /**
9242          * Creates an iframe shim for this element to keep selects and other windowed objects from
9243          * showing through.
9244          * @return {Roo.Element} The new shim element
9245          */
9246         createShim : function(){
9247             var el = document.createElement('iframe');
9248             el.frameBorder = 'no';
9249             el.className = 'roo-shim';
9250             if(Roo.isIE && Roo.isSecure){
9251                 el.src = Roo.SSL_SECURE_URL;
9252             }
9253             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9254             shim.autoBoxAdjust = false;
9255             return shim;
9256         },
9257
9258         /**
9259          * Removes this element from the DOM and deletes it from the cache
9260          */
9261         remove : function(){
9262             if(this.dom.parentNode){
9263                 this.dom.parentNode.removeChild(this.dom);
9264             }
9265             delete El.cache[this.dom.id];
9266         },
9267
9268         /**
9269          * Sets up event handlers to add and remove a css class when the mouse is over this element
9270          * @param {String} className
9271          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9272          * mouseout events for children elements
9273          * @return {Roo.Element} this
9274          */
9275         addClassOnOver : function(className, preventFlicker){
9276             this.on("mouseover", function(){
9277                 Roo.fly(this, '_internal').addClass(className);
9278             }, this.dom);
9279             var removeFn = function(e){
9280                 if(preventFlicker !== true || !e.within(this, true)){
9281                     Roo.fly(this, '_internal').removeClass(className);
9282                 }
9283             };
9284             this.on("mouseout", removeFn, this.dom);
9285             return this;
9286         },
9287
9288         /**
9289          * Sets up event handlers to add and remove a css class when this element has the focus
9290          * @param {String} className
9291          * @return {Roo.Element} this
9292          */
9293         addClassOnFocus : function(className){
9294             this.on("focus", function(){
9295                 Roo.fly(this, '_internal').addClass(className);
9296             }, this.dom);
9297             this.on("blur", function(){
9298                 Roo.fly(this, '_internal').removeClass(className);
9299             }, this.dom);
9300             return this;
9301         },
9302         /**
9303          * 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)
9304          * @param {String} className
9305          * @return {Roo.Element} this
9306          */
9307         addClassOnClick : function(className){
9308             var dom = this.dom;
9309             this.on("mousedown", function(){
9310                 Roo.fly(dom, '_internal').addClass(className);
9311                 var d = Roo.get(document);
9312                 var fn = function(){
9313                     Roo.fly(dom, '_internal').removeClass(className);
9314                     d.removeListener("mouseup", fn);
9315                 };
9316                 d.on("mouseup", fn);
9317             });
9318             return this;
9319         },
9320
9321         /**
9322          * Stops the specified event from bubbling and optionally prevents the default action
9323          * @param {String} eventName
9324          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9325          * @return {Roo.Element} this
9326          */
9327         swallowEvent : function(eventName, preventDefault){
9328             var fn = function(e){
9329                 e.stopPropagation();
9330                 if(preventDefault){
9331                     e.preventDefault();
9332                 }
9333             };
9334             if(eventName instanceof Array){
9335                 for(var i = 0, len = eventName.length; i < len; i++){
9336                      this.on(eventName[i], fn);
9337                 }
9338                 return this;
9339             }
9340             this.on(eventName, fn);
9341             return this;
9342         },
9343
9344         /**
9345          * @private
9346          */
9347       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9348
9349         /**
9350          * Sizes this element to its parent element's dimensions performing
9351          * neccessary box adjustments.
9352          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9353          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9354          * @return {Roo.Element} this
9355          */
9356         fitToParent : function(monitorResize, targetParent) {
9357           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9358           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9359           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9360             return;
9361           }
9362           var p = Roo.get(targetParent || this.dom.parentNode);
9363           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9364           if (monitorResize === true) {
9365             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9366             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9367           }
9368           return this;
9369         },
9370
9371         /**
9372          * Gets the next sibling, skipping text nodes
9373          * @return {HTMLElement} The next sibling or null
9374          */
9375         getNextSibling : function(){
9376             var n = this.dom.nextSibling;
9377             while(n && n.nodeType != 1){
9378                 n = n.nextSibling;
9379             }
9380             return n;
9381         },
9382
9383         /**
9384          * Gets the previous sibling, skipping text nodes
9385          * @return {HTMLElement} The previous sibling or null
9386          */
9387         getPrevSibling : function(){
9388             var n = this.dom.previousSibling;
9389             while(n && n.nodeType != 1){
9390                 n = n.previousSibling;
9391             }
9392             return n;
9393         },
9394
9395
9396         /**
9397          * Appends the passed element(s) to this element
9398          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9399          * @return {Roo.Element} this
9400          */
9401         appendChild: function(el){
9402             el = Roo.get(el);
9403             el.appendTo(this);
9404             return this;
9405         },
9406
9407         /**
9408          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9409          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9410          * automatically generated with the specified attributes.
9411          * @param {HTMLElement} insertBefore (optional) a child element of this element
9412          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9413          * @return {Roo.Element} The new child element
9414          */
9415         createChild: function(config, insertBefore, returnDom){
9416             config = config || {tag:'div'};
9417             if(insertBefore){
9418                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9419             }
9420             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9421         },
9422
9423         /**
9424          * Appends this element to the passed element
9425          * @param {String/HTMLElement/Element} el The new parent element
9426          * @return {Roo.Element} this
9427          */
9428         appendTo: function(el){
9429             el = Roo.getDom(el);
9430             el.appendChild(this.dom);
9431             return this;
9432         },
9433
9434         /**
9435          * Inserts this element before the passed element in the DOM
9436          * @param {String/HTMLElement/Element} el The element to insert before
9437          * @return {Roo.Element} this
9438          */
9439         insertBefore: function(el){
9440             el = Roo.getDom(el);
9441             el.parentNode.insertBefore(this.dom, el);
9442             return this;
9443         },
9444
9445         /**
9446          * Inserts this element after the passed element in the DOM
9447          * @param {String/HTMLElement/Element} el The element to insert after
9448          * @return {Roo.Element} this
9449          */
9450         insertAfter: function(el){
9451             el = Roo.getDom(el);
9452             el.parentNode.insertBefore(this.dom, el.nextSibling);
9453             return this;
9454         },
9455
9456         /**
9457          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9458          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9459          * @return {Roo.Element} The new child
9460          */
9461         insertFirst: function(el, returnDom){
9462             el = el || {};
9463             if(typeof el == 'object' && !el.nodeType){ // dh config
9464                 return this.createChild(el, this.dom.firstChild, returnDom);
9465             }else{
9466                 el = Roo.getDom(el);
9467                 this.dom.insertBefore(el, this.dom.firstChild);
9468                 return !returnDom ? Roo.get(el) : el;
9469             }
9470         },
9471
9472         /**
9473          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9474          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9475          * @param {String} where (optional) 'before' or 'after' defaults to before
9476          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9477          * @return {Roo.Element} the inserted Element
9478          */
9479         insertSibling: function(el, where, returnDom){
9480             where = where ? where.toLowerCase() : 'before';
9481             el = el || {};
9482             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9483
9484             if(typeof el == 'object' && !el.nodeType){ // dh config
9485                 if(where == 'after' && !this.dom.nextSibling){
9486                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9487                 }else{
9488                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9489                 }
9490
9491             }else{
9492                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9493                             where == 'before' ? this.dom : this.dom.nextSibling);
9494                 if(!returnDom){
9495                     rt = Roo.get(rt);
9496                 }
9497             }
9498             return rt;
9499         },
9500
9501         /**
9502          * Creates and wraps this element with another element
9503          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9504          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9505          * @return {HTMLElement/Element} The newly created wrapper element
9506          */
9507         wrap: function(config, returnDom){
9508             if(!config){
9509                 config = {tag: "div"};
9510             }
9511             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9512             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9513             return newEl;
9514         },
9515
9516         /**
9517          * Replaces the passed element with this element
9518          * @param {String/HTMLElement/Element} el The element to replace
9519          * @return {Roo.Element} this
9520          */
9521         replace: function(el){
9522             el = Roo.get(el);
9523             this.insertBefore(el);
9524             el.remove();
9525             return this;
9526         },
9527
9528         /**
9529          * Inserts an html fragment into this element
9530          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9531          * @param {String} html The HTML fragment
9532          * @param {Boolean} returnEl True to return an Roo.Element
9533          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9534          */
9535         insertHtml : function(where, html, returnEl){
9536             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9537             return returnEl ? Roo.get(el) : el;
9538         },
9539
9540         /**
9541          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9542          * @param {Object} o The object with the attributes
9543          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9544          * @return {Roo.Element} this
9545          */
9546         set : function(o, useSet){
9547             var el = this.dom;
9548             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9549             for(var attr in o){
9550                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9551                 if(attr=="cls"){
9552                     el.className = o["cls"];
9553                 }else{
9554                     if(useSet) {
9555                         el.setAttribute(attr, o[attr]);
9556                     } else {
9557                         el[attr] = o[attr];
9558                     }
9559                 }
9560             }
9561             if(o.style){
9562                 Roo.DomHelper.applyStyles(el, o.style);
9563             }
9564             return this;
9565         },
9566
9567         /**
9568          * Convenience method for constructing a KeyMap
9569          * @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:
9570          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9571          * @param {Function} fn The function to call
9572          * @param {Object} scope (optional) The scope of the function
9573          * @return {Roo.KeyMap} The KeyMap created
9574          */
9575         addKeyListener : function(key, fn, scope){
9576             var config;
9577             if(typeof key != "object" || key instanceof Array){
9578                 config = {
9579                     key: key,
9580                     fn: fn,
9581                     scope: scope
9582                 };
9583             }else{
9584                 config = {
9585                     key : key.key,
9586                     shift : key.shift,
9587                     ctrl : key.ctrl,
9588                     alt : key.alt,
9589                     fn: fn,
9590                     scope: scope
9591                 };
9592             }
9593             return new Roo.KeyMap(this, config);
9594         },
9595
9596         /**
9597          * Creates a KeyMap for this element
9598          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9599          * @return {Roo.KeyMap} The KeyMap created
9600          */
9601         addKeyMap : function(config){
9602             return new Roo.KeyMap(this, config);
9603         },
9604
9605         /**
9606          * Returns true if this element is scrollable.
9607          * @return {Boolean}
9608          */
9609          isScrollable : function(){
9610             var dom = this.dom;
9611             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9612         },
9613
9614         /**
9615          * 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().
9616          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9617          * @param {Number} value The new scroll value
9618          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9619          * @return {Element} this
9620          */
9621
9622         scrollTo : function(side, value, animate){
9623             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9624             if(!animate || !A){
9625                 this.dom[prop] = value;
9626             }else{
9627                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9628                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9629             }
9630             return this;
9631         },
9632
9633         /**
9634          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9635          * within this element's scrollable range.
9636          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9637          * @param {Number} distance How far to scroll the element in pixels
9638          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9639          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9640          * was scrolled as far as it could go.
9641          */
9642          scroll : function(direction, distance, animate){
9643              if(!this.isScrollable()){
9644                  return;
9645              }
9646              var el = this.dom;
9647              var l = el.scrollLeft, t = el.scrollTop;
9648              var w = el.scrollWidth, h = el.scrollHeight;
9649              var cw = el.clientWidth, ch = el.clientHeight;
9650              direction = direction.toLowerCase();
9651              var scrolled = false;
9652              var a = this.preanim(arguments, 2);
9653              switch(direction){
9654                  case "l":
9655                  case "left":
9656                      if(w - l > cw){
9657                          var v = Math.min(l + distance, w-cw);
9658                          this.scrollTo("left", v, a);
9659                          scrolled = true;
9660                      }
9661                      break;
9662                 case "r":
9663                 case "right":
9664                      if(l > 0){
9665                          var v = Math.max(l - distance, 0);
9666                          this.scrollTo("left", v, a);
9667                          scrolled = true;
9668                      }
9669                      break;
9670                 case "t":
9671                 case "top":
9672                 case "up":
9673                      if(t > 0){
9674                          var v = Math.max(t - distance, 0);
9675                          this.scrollTo("top", v, a);
9676                          scrolled = true;
9677                      }
9678                      break;
9679                 case "b":
9680                 case "bottom":
9681                 case "down":
9682                      if(h - t > ch){
9683                          var v = Math.min(t + distance, h-ch);
9684                          this.scrollTo("top", v, a);
9685                          scrolled = true;
9686                      }
9687                      break;
9688              }
9689              return scrolled;
9690         },
9691
9692         /**
9693          * Translates the passed page coordinates into left/top css values for this element
9694          * @param {Number/Array} x The page x or an array containing [x, y]
9695          * @param {Number} y The page y
9696          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9697          */
9698         translatePoints : function(x, y){
9699             if(typeof x == 'object' || x instanceof Array){
9700                 y = x[1]; x = x[0];
9701             }
9702             var p = this.getStyle('position');
9703             var o = this.getXY();
9704
9705             var l = parseInt(this.getStyle('left'), 10);
9706             var t = parseInt(this.getStyle('top'), 10);
9707
9708             if(isNaN(l)){
9709                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9710             }
9711             if(isNaN(t)){
9712                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9713             }
9714
9715             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9716         },
9717
9718         /**
9719          * Returns the current scroll position of the element.
9720          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9721          */
9722         getScroll : function(){
9723             var d = this.dom, doc = document;
9724             if(d == doc || d == doc.body){
9725                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9726                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9727                 return {left: l, top: t};
9728             }else{
9729                 return {left: d.scrollLeft, top: d.scrollTop};
9730             }
9731         },
9732
9733         /**
9734          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9735          * are convert to standard 6 digit hex color.
9736          * @param {String} attr The css attribute
9737          * @param {String} defaultValue The default value to use when a valid color isn't found
9738          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9739          * YUI color anims.
9740          */
9741         getColor : function(attr, defaultValue, prefix){
9742             var v = this.getStyle(attr);
9743             if(!v || v == "transparent" || v == "inherit") {
9744                 return defaultValue;
9745             }
9746             var color = typeof prefix == "undefined" ? "#" : prefix;
9747             if(v.substr(0, 4) == "rgb("){
9748                 var rvs = v.slice(4, v.length -1).split(",");
9749                 for(var i = 0; i < 3; i++){
9750                     var h = parseInt(rvs[i]).toString(16);
9751                     if(h < 16){
9752                         h = "0" + h;
9753                     }
9754                     color += h;
9755                 }
9756             } else {
9757                 if(v.substr(0, 1) == "#"){
9758                     if(v.length == 4) {
9759                         for(var i = 1; i < 4; i++){
9760                             var c = v.charAt(i);
9761                             color +=  c + c;
9762                         }
9763                     }else if(v.length == 7){
9764                         color += v.substr(1);
9765                     }
9766                 }
9767             }
9768             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9769         },
9770
9771         /**
9772          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9773          * gradient background, rounded corners and a 4-way shadow.
9774          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9775          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9776          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9777          * @return {Roo.Element} this
9778          */
9779         boxWrap : function(cls){
9780             cls = cls || 'x-box';
9781             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9782             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9783             return el;
9784         },
9785
9786         /**
9787          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9788          * @param {String} namespace The namespace in which to look for the attribute
9789          * @param {String} name The attribute name
9790          * @return {String} The attribute value
9791          */
9792         getAttributeNS : Roo.isIE ? function(ns, name){
9793             var d = this.dom;
9794             var type = typeof d[ns+":"+name];
9795             if(type != 'undefined' && type != 'unknown'){
9796                 return d[ns+":"+name];
9797             }
9798             return d[name];
9799         } : function(ns, name){
9800             var d = this.dom;
9801             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9802         },
9803         
9804         
9805         /**
9806          * Sets or Returns the value the dom attribute value
9807          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9808          * @param {String} value (optional) The value to set the attribute to
9809          * @return {String} The attribute value
9810          */
9811         attr : function(name){
9812             if (arguments.length > 1) {
9813                 this.dom.setAttribute(name, arguments[1]);
9814                 return arguments[1];
9815             }
9816             if (typeof(name) == 'object') {
9817                 for(var i in name) {
9818                     this.attr(i, name[i]);
9819                 }
9820                 return name;
9821             }
9822             
9823             
9824             if (!this.dom.hasAttribute(name)) {
9825                 return undefined;
9826             }
9827             return this.dom.getAttribute(name);
9828         }
9829         
9830         
9831         
9832     };
9833
9834     var ep = El.prototype;
9835
9836     /**
9837      * Appends an event handler (Shorthand for addListener)
9838      * @param {String}   eventName     The type of event to append
9839      * @param {Function} fn        The method the event invokes
9840      * @param {Object} scope       (optional) The scope (this object) of the fn
9841      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9842      * @method
9843      */
9844     ep.on = ep.addListener;
9845         // backwards compat
9846     ep.mon = ep.addListener;
9847
9848     /**
9849      * Removes an event handler from this element (shorthand for removeListener)
9850      * @param {String} eventName the type of event to remove
9851      * @param {Function} fn the method the event invokes
9852      * @return {Roo.Element} this
9853      * @method
9854      */
9855     ep.un = ep.removeListener;
9856
9857     /**
9858      * true to automatically adjust width and height settings for box-model issues (default to true)
9859      */
9860     ep.autoBoxAdjust = true;
9861
9862     // private
9863     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9864
9865     // private
9866     El.addUnits = function(v, defaultUnit){
9867         if(v === "" || v == "auto"){
9868             return v;
9869         }
9870         if(v === undefined){
9871             return '';
9872         }
9873         if(typeof v == "number" || !El.unitPattern.test(v)){
9874             return v + (defaultUnit || 'px');
9875         }
9876         return v;
9877     };
9878
9879     // special markup used throughout Roo when box wrapping elements
9880     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>';
9881     /**
9882      * Visibility mode constant - Use visibility to hide element
9883      * @static
9884      * @type Number
9885      */
9886     El.VISIBILITY = 1;
9887     /**
9888      * Visibility mode constant - Use display to hide element
9889      * @static
9890      * @type Number
9891      */
9892     El.DISPLAY = 2;
9893
9894     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9895     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9896     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9897
9898
9899
9900     /**
9901      * @private
9902      */
9903     El.cache = {};
9904
9905     var docEl;
9906
9907     /**
9908      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9909      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9910      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9911      * @return {Element} The Element object
9912      * @static
9913      */
9914     El.get = function(el){
9915         var ex, elm, id;
9916         if(!el){ return null; }
9917         if(typeof el == "string"){ // element id
9918             if(!(elm = document.getElementById(el))){
9919                 return null;
9920             }
9921             if(ex = El.cache[el]){
9922                 ex.dom = elm;
9923             }else{
9924                 ex = El.cache[el] = new El(elm);
9925             }
9926             return ex;
9927         }else if(el.tagName){ // dom element
9928             if(!(id = el.id)){
9929                 id = Roo.id(el);
9930             }
9931             if(ex = El.cache[id]){
9932                 ex.dom = el;
9933             }else{
9934                 ex = El.cache[id] = new El(el);
9935             }
9936             return ex;
9937         }else if(el instanceof El){
9938             if(el != docEl){
9939                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9940                                                               // catch case where it hasn't been appended
9941                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9942             }
9943             return el;
9944         }else if(el.isComposite){
9945             return el;
9946         }else if(el instanceof Array){
9947             return El.select(el);
9948         }else if(el == document){
9949             // create a bogus element object representing the document object
9950             if(!docEl){
9951                 var f = function(){};
9952                 f.prototype = El.prototype;
9953                 docEl = new f();
9954                 docEl.dom = document;
9955             }
9956             return docEl;
9957         }
9958         return null;
9959     };
9960
9961     // private
9962     El.uncache = function(el){
9963         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9964             if(a[i]){
9965                 delete El.cache[a[i].id || a[i]];
9966             }
9967         }
9968     };
9969
9970     // private
9971     // Garbage collection - uncache elements/purge listeners on orphaned elements
9972     // so we don't hold a reference and cause the browser to retain them
9973     El.garbageCollect = function(){
9974         if(!Roo.enableGarbageCollector){
9975             clearInterval(El.collectorThread);
9976             return;
9977         }
9978         for(var eid in El.cache){
9979             var el = El.cache[eid], d = el.dom;
9980             // -------------------------------------------------------
9981             // Determining what is garbage:
9982             // -------------------------------------------------------
9983             // !d
9984             // dom node is null, definitely garbage
9985             // -------------------------------------------------------
9986             // !d.parentNode
9987             // no parentNode == direct orphan, definitely garbage
9988             // -------------------------------------------------------
9989             // !d.offsetParent && !document.getElementById(eid)
9990             // display none elements have no offsetParent so we will
9991             // also try to look it up by it's id. However, check
9992             // offsetParent first so we don't do unneeded lookups.
9993             // This enables collection of elements that are not orphans
9994             // directly, but somewhere up the line they have an orphan
9995             // parent.
9996             // -------------------------------------------------------
9997             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9998                 delete El.cache[eid];
9999                 if(d && Roo.enableListenerCollection){
10000                     E.purgeElement(d);
10001                 }
10002             }
10003         }
10004     }
10005     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10006
10007
10008     // dom is optional
10009     El.Flyweight = function(dom){
10010         this.dom = dom;
10011     };
10012     El.Flyweight.prototype = El.prototype;
10013
10014     El._flyweights = {};
10015     /**
10016      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10017      * the dom node can be overwritten by other code.
10018      * @param {String/HTMLElement} el The dom node or id
10019      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10020      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10021      * @static
10022      * @return {Element} The shared Element object
10023      */
10024     El.fly = function(el, named){
10025         named = named || '_global';
10026         el = Roo.getDom(el);
10027         if(!el){
10028             return null;
10029         }
10030         if(!El._flyweights[named]){
10031             El._flyweights[named] = new El.Flyweight();
10032         }
10033         El._flyweights[named].dom = el;
10034         return El._flyweights[named];
10035     };
10036
10037     /**
10038      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10039      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10040      * Shorthand of {@link Roo.Element#get}
10041      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10042      * @return {Element} The Element object
10043      * @member Roo
10044      * @method get
10045      */
10046     Roo.get = El.get;
10047     /**
10048      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10049      * the dom node can be overwritten by other code.
10050      * Shorthand of {@link Roo.Element#fly}
10051      * @param {String/HTMLElement} el The dom node or id
10052      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10053      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10054      * @static
10055      * @return {Element} The shared Element object
10056      * @member Roo
10057      * @method fly
10058      */
10059     Roo.fly = El.fly;
10060
10061     // speedy lookup for elements never to box adjust
10062     var noBoxAdjust = Roo.isStrict ? {
10063         select:1
10064     } : {
10065         input:1, select:1, textarea:1
10066     };
10067     if(Roo.isIE || Roo.isGecko){
10068         noBoxAdjust['button'] = 1;
10069     }
10070
10071
10072     Roo.EventManager.on(window, 'unload', function(){
10073         delete El.cache;
10074         delete El._flyweights;
10075     });
10076 })();
10077
10078
10079
10080
10081 if(Roo.DomQuery){
10082     Roo.Element.selectorFunction = Roo.DomQuery.select;
10083 }
10084
10085 Roo.Element.select = function(selector, unique, root){
10086     var els;
10087     if(typeof selector == "string"){
10088         els = Roo.Element.selectorFunction(selector, root);
10089     }else if(selector.length !== undefined){
10090         els = selector;
10091     }else{
10092         throw "Invalid selector";
10093     }
10094     if(unique === true){
10095         return new Roo.CompositeElement(els);
10096     }else{
10097         return new Roo.CompositeElementLite(els);
10098     }
10099 };
10100 /**
10101  * Selects elements based on the passed CSS selector to enable working on them as 1.
10102  * @param {String/Array} selector The CSS selector or an array of elements
10103  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10104  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10105  * @return {CompositeElementLite/CompositeElement}
10106  * @member Roo
10107  * @method select
10108  */
10109 Roo.select = Roo.Element.select;
10110
10111
10112
10113
10114
10115
10116
10117
10118
10119
10120
10121
10122
10123
10124 /*
10125  * Based on:
10126  * Ext JS Library 1.1.1
10127  * Copyright(c) 2006-2007, Ext JS, LLC.
10128  *
10129  * Originally Released Under LGPL - original licence link has changed is not relivant.
10130  *
10131  * Fork - LGPL
10132  * <script type="text/javascript">
10133  */
10134
10135
10136
10137 //Notifies Element that fx methods are available
10138 Roo.enableFx = true;
10139
10140 /**
10141  * @class Roo.Fx
10142  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10143  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10144  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10145  * Element effects to work.</p><br/>
10146  *
10147  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10148  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10149  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10150  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10151  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10152  * expected results and should be done with care.</p><br/>
10153  *
10154  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10155  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10156 <pre>
10157 Value  Description
10158 -----  -----------------------------
10159 tl     The top left corner
10160 t      The center of the top edge
10161 tr     The top right corner
10162 l      The center of the left edge
10163 r      The center of the right edge
10164 bl     The bottom left corner
10165 b      The center of the bottom edge
10166 br     The bottom right corner
10167 </pre>
10168  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10169  * below are common options that can be passed to any Fx method.</b>
10170  * @cfg {Function} callback A function called when the effect is finished
10171  * @cfg {Object} scope The scope of the effect function
10172  * @cfg {String} easing A valid Easing value for the effect
10173  * @cfg {String} afterCls A css class to apply after the effect
10174  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10175  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10176  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10177  * effects that end with the element being visually hidden, ignored otherwise)
10178  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10179  * a function which returns such a specification that will be applied to the Element after the effect finishes
10180  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10181  * @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
10182  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10183  */
10184 Roo.Fx = {
10185         /**
10186          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10187          * origin for the slide effect.  This function automatically handles wrapping the element with
10188          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10189          * Usage:
10190          *<pre><code>
10191 // default: slide the element in from the top
10192 el.slideIn();
10193
10194 // custom: slide the element in from the right with a 2-second duration
10195 el.slideIn('r', { duration: 2 });
10196
10197 // common config options shown with default values
10198 el.slideIn('t', {
10199     easing: 'easeOut',
10200     duration: .5
10201 });
10202 </code></pre>
10203          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10204          * @param {Object} options (optional) Object literal with any of the Fx config options
10205          * @return {Roo.Element} The Element
10206          */
10207     slideIn : function(anchor, o){
10208         var el = this.getFxEl();
10209         o = o || {};
10210
10211         el.queueFx(o, function(){
10212
10213             anchor = anchor || "t";
10214
10215             // fix display to visibility
10216             this.fixDisplay();
10217
10218             // restore values after effect
10219             var r = this.getFxRestore();
10220             var b = this.getBox();
10221             // fixed size for slide
10222             this.setSize(b);
10223
10224             // wrap if needed
10225             var wrap = this.fxWrap(r.pos, o, "hidden");
10226
10227             var st = this.dom.style;
10228             st.visibility = "visible";
10229             st.position = "absolute";
10230
10231             // clear out temp styles after slide and unwrap
10232             var after = function(){
10233                 el.fxUnwrap(wrap, r.pos, o);
10234                 st.width = r.width;
10235                 st.height = r.height;
10236                 el.afterFx(o);
10237             };
10238             // time to calc the positions
10239             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10240
10241             switch(anchor.toLowerCase()){
10242                 case "t":
10243                     wrap.setSize(b.width, 0);
10244                     st.left = st.bottom = "0";
10245                     a = {height: bh};
10246                 break;
10247                 case "l":
10248                     wrap.setSize(0, b.height);
10249                     st.right = st.top = "0";
10250                     a = {width: bw};
10251                 break;
10252                 case "r":
10253                     wrap.setSize(0, b.height);
10254                     wrap.setX(b.right);
10255                     st.left = st.top = "0";
10256                     a = {width: bw, points: pt};
10257                 break;
10258                 case "b":
10259                     wrap.setSize(b.width, 0);
10260                     wrap.setY(b.bottom);
10261                     st.left = st.top = "0";
10262                     a = {height: bh, points: pt};
10263                 break;
10264                 case "tl":
10265                     wrap.setSize(0, 0);
10266                     st.right = st.bottom = "0";
10267                     a = {width: bw, height: bh};
10268                 break;
10269                 case "bl":
10270                     wrap.setSize(0, 0);
10271                     wrap.setY(b.y+b.height);
10272                     st.right = st.top = "0";
10273                     a = {width: bw, height: bh, points: pt};
10274                 break;
10275                 case "br":
10276                     wrap.setSize(0, 0);
10277                     wrap.setXY([b.right, b.bottom]);
10278                     st.left = st.top = "0";
10279                     a = {width: bw, height: bh, points: pt};
10280                 break;
10281                 case "tr":
10282                     wrap.setSize(0, 0);
10283                     wrap.setX(b.x+b.width);
10284                     st.left = st.bottom = "0";
10285                     a = {width: bw, height: bh, points: pt};
10286                 break;
10287             }
10288             this.dom.style.visibility = "visible";
10289             wrap.show();
10290
10291             arguments.callee.anim = wrap.fxanim(a,
10292                 o,
10293                 'motion',
10294                 .5,
10295                 'easeOut', after);
10296         });
10297         return this;
10298     },
10299     
10300         /**
10301          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10302          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10303          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10304          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10305          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10306          * Usage:
10307          *<pre><code>
10308 // default: slide the element out to the top
10309 el.slideOut();
10310
10311 // custom: slide the element out to the right with a 2-second duration
10312 el.slideOut('r', { duration: 2 });
10313
10314 // common config options shown with default values
10315 el.slideOut('t', {
10316     easing: 'easeOut',
10317     duration: .5,
10318     remove: false,
10319     useDisplay: false
10320 });
10321 </code></pre>
10322          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10323          * @param {Object} options (optional) Object literal with any of the Fx config options
10324          * @return {Roo.Element} The Element
10325          */
10326     slideOut : function(anchor, o){
10327         var el = this.getFxEl();
10328         o = o || {};
10329
10330         el.queueFx(o, function(){
10331
10332             anchor = anchor || "t";
10333
10334             // restore values after effect
10335             var r = this.getFxRestore();
10336             
10337             var b = this.getBox();
10338             // fixed size for slide
10339             this.setSize(b);
10340
10341             // wrap if needed
10342             var wrap = this.fxWrap(r.pos, o, "visible");
10343
10344             var st = this.dom.style;
10345             st.visibility = "visible";
10346             st.position = "absolute";
10347
10348             wrap.setSize(b);
10349
10350             var after = function(){
10351                 if(o.useDisplay){
10352                     el.setDisplayed(false);
10353                 }else{
10354                     el.hide();
10355                 }
10356
10357                 el.fxUnwrap(wrap, r.pos, o);
10358
10359                 st.width = r.width;
10360                 st.height = r.height;
10361
10362                 el.afterFx(o);
10363             };
10364
10365             var a, zero = {to: 0};
10366             switch(anchor.toLowerCase()){
10367                 case "t":
10368                     st.left = st.bottom = "0";
10369                     a = {height: zero};
10370                 break;
10371                 case "l":
10372                     st.right = st.top = "0";
10373                     a = {width: zero};
10374                 break;
10375                 case "r":
10376                     st.left = st.top = "0";
10377                     a = {width: zero, points: {to:[b.right, b.y]}};
10378                 break;
10379                 case "b":
10380                     st.left = st.top = "0";
10381                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10382                 break;
10383                 case "tl":
10384                     st.right = st.bottom = "0";
10385                     a = {width: zero, height: zero};
10386                 break;
10387                 case "bl":
10388                     st.right = st.top = "0";
10389                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10390                 break;
10391                 case "br":
10392                     st.left = st.top = "0";
10393                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10394                 break;
10395                 case "tr":
10396                     st.left = st.bottom = "0";
10397                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10398                 break;
10399             }
10400
10401             arguments.callee.anim = wrap.fxanim(a,
10402                 o,
10403                 'motion',
10404                 .5,
10405                 "easeOut", after);
10406         });
10407         return this;
10408     },
10409
10410         /**
10411          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10412          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10413          * The element must be removed from the DOM using the 'remove' config option if desired.
10414          * Usage:
10415          *<pre><code>
10416 // default
10417 el.puff();
10418
10419 // common config options shown with default values
10420 el.puff({
10421     easing: 'easeOut',
10422     duration: .5,
10423     remove: false,
10424     useDisplay: false
10425 });
10426 </code></pre>
10427          * @param {Object} options (optional) Object literal with any of the Fx config options
10428          * @return {Roo.Element} The Element
10429          */
10430     puff : function(o){
10431         var el = this.getFxEl();
10432         o = o || {};
10433
10434         el.queueFx(o, function(){
10435             this.clearOpacity();
10436             this.show();
10437
10438             // restore values after effect
10439             var r = this.getFxRestore();
10440             var st = this.dom.style;
10441
10442             var after = function(){
10443                 if(o.useDisplay){
10444                     el.setDisplayed(false);
10445                 }else{
10446                     el.hide();
10447                 }
10448
10449                 el.clearOpacity();
10450
10451                 el.setPositioning(r.pos);
10452                 st.width = r.width;
10453                 st.height = r.height;
10454                 st.fontSize = '';
10455                 el.afterFx(o);
10456             };
10457
10458             var width = this.getWidth();
10459             var height = this.getHeight();
10460
10461             arguments.callee.anim = this.fxanim({
10462                     width : {to: this.adjustWidth(width * 2)},
10463                     height : {to: this.adjustHeight(height * 2)},
10464                     points : {by: [-(width * .5), -(height * .5)]},
10465                     opacity : {to: 0},
10466                     fontSize: {to:200, unit: "%"}
10467                 },
10468                 o,
10469                 'motion',
10470                 .5,
10471                 "easeOut", after);
10472         });
10473         return this;
10474     },
10475
10476         /**
10477          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10478          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10479          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10480          * Usage:
10481          *<pre><code>
10482 // default
10483 el.switchOff();
10484
10485 // all config options shown with default values
10486 el.switchOff({
10487     easing: 'easeIn',
10488     duration: .3,
10489     remove: false,
10490     useDisplay: false
10491 });
10492 </code></pre>
10493          * @param {Object} options (optional) Object literal with any of the Fx config options
10494          * @return {Roo.Element} The Element
10495          */
10496     switchOff : function(o){
10497         var el = this.getFxEl();
10498         o = o || {};
10499
10500         el.queueFx(o, function(){
10501             this.clearOpacity();
10502             this.clip();
10503
10504             // restore values after effect
10505             var r = this.getFxRestore();
10506             var st = this.dom.style;
10507
10508             var after = function(){
10509                 if(o.useDisplay){
10510                     el.setDisplayed(false);
10511                 }else{
10512                     el.hide();
10513                 }
10514
10515                 el.clearOpacity();
10516                 el.setPositioning(r.pos);
10517                 st.width = r.width;
10518                 st.height = r.height;
10519
10520                 el.afterFx(o);
10521             };
10522
10523             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10524                 this.clearOpacity();
10525                 (function(){
10526                     this.fxanim({
10527                         height:{to:1},
10528                         points:{by:[0, this.getHeight() * .5]}
10529                     }, o, 'motion', 0.3, 'easeIn', after);
10530                 }).defer(100, this);
10531             });
10532         });
10533         return this;
10534     },
10535
10536     /**
10537      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10538      * changed using the "attr" config option) and then fading back to the original color. If no original
10539      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10540      * Usage:
10541 <pre><code>
10542 // default: highlight background to yellow
10543 el.highlight();
10544
10545 // custom: highlight foreground text to blue for 2 seconds
10546 el.highlight("0000ff", { attr: 'color', duration: 2 });
10547
10548 // common config options shown with default values
10549 el.highlight("ffff9c", {
10550     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10551     endColor: (current color) or "ffffff",
10552     easing: 'easeIn',
10553     duration: 1
10554 });
10555 </code></pre>
10556      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10557      * @param {Object} options (optional) Object literal with any of the Fx config options
10558      * @return {Roo.Element} The Element
10559      */ 
10560     highlight : function(color, o){
10561         var el = this.getFxEl();
10562         o = o || {};
10563
10564         el.queueFx(o, function(){
10565             color = color || "ffff9c";
10566             attr = o.attr || "backgroundColor";
10567
10568             this.clearOpacity();
10569             this.show();
10570
10571             var origColor = this.getColor(attr);
10572             var restoreColor = this.dom.style[attr];
10573             endColor = (o.endColor || origColor) || "ffffff";
10574
10575             var after = function(){
10576                 el.dom.style[attr] = restoreColor;
10577                 el.afterFx(o);
10578             };
10579
10580             var a = {};
10581             a[attr] = {from: color, to: endColor};
10582             arguments.callee.anim = this.fxanim(a,
10583                 o,
10584                 'color',
10585                 1,
10586                 'easeIn', after);
10587         });
10588         return this;
10589     },
10590
10591    /**
10592     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10593     * Usage:
10594 <pre><code>
10595 // default: a single light blue ripple
10596 el.frame();
10597
10598 // custom: 3 red ripples lasting 3 seconds total
10599 el.frame("ff0000", 3, { duration: 3 });
10600
10601 // common config options shown with default values
10602 el.frame("C3DAF9", 1, {
10603     duration: 1 //duration of entire animation (not each individual ripple)
10604     // Note: Easing is not configurable and will be ignored if included
10605 });
10606 </code></pre>
10607     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10608     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10609     * @param {Object} options (optional) Object literal with any of the Fx config options
10610     * @return {Roo.Element} The Element
10611     */
10612     frame : function(color, count, o){
10613         var el = this.getFxEl();
10614         o = o || {};
10615
10616         el.queueFx(o, function(){
10617             color = color || "#C3DAF9";
10618             if(color.length == 6){
10619                 color = "#" + color;
10620             }
10621             count = count || 1;
10622             duration = o.duration || 1;
10623             this.show();
10624
10625             var b = this.getBox();
10626             var animFn = function(){
10627                 var proxy = this.createProxy({
10628
10629                      style:{
10630                         visbility:"hidden",
10631                         position:"absolute",
10632                         "z-index":"35000", // yee haw
10633                         border:"0px solid " + color
10634                      }
10635                   });
10636                 var scale = Roo.isBorderBox ? 2 : 1;
10637                 proxy.animate({
10638                     top:{from:b.y, to:b.y - 20},
10639                     left:{from:b.x, to:b.x - 20},
10640                     borderWidth:{from:0, to:10},
10641                     opacity:{from:1, to:0},
10642                     height:{from:b.height, to:(b.height + (20*scale))},
10643                     width:{from:b.width, to:(b.width + (20*scale))}
10644                 }, duration, function(){
10645                     proxy.remove();
10646                 });
10647                 if(--count > 0){
10648                      animFn.defer((duration/2)*1000, this);
10649                 }else{
10650                     el.afterFx(o);
10651                 }
10652             };
10653             animFn.call(this);
10654         });
10655         return this;
10656     },
10657
10658    /**
10659     * Creates a pause before any subsequent queued effects begin.  If there are
10660     * no effects queued after the pause it will have no effect.
10661     * Usage:
10662 <pre><code>
10663 el.pause(1);
10664 </code></pre>
10665     * @param {Number} seconds The length of time to pause (in seconds)
10666     * @return {Roo.Element} The Element
10667     */
10668     pause : function(seconds){
10669         var el = this.getFxEl();
10670         var o = {};
10671
10672         el.queueFx(o, function(){
10673             setTimeout(function(){
10674                 el.afterFx(o);
10675             }, seconds * 1000);
10676         });
10677         return this;
10678     },
10679
10680    /**
10681     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10682     * using the "endOpacity" config option.
10683     * Usage:
10684 <pre><code>
10685 // default: fade in from opacity 0 to 100%
10686 el.fadeIn();
10687
10688 // custom: fade in from opacity 0 to 75% over 2 seconds
10689 el.fadeIn({ endOpacity: .75, duration: 2});
10690
10691 // common config options shown with default values
10692 el.fadeIn({
10693     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10694     easing: 'easeOut',
10695     duration: .5
10696 });
10697 </code></pre>
10698     * @param {Object} options (optional) Object literal with any of the Fx config options
10699     * @return {Roo.Element} The Element
10700     */
10701     fadeIn : function(o){
10702         var el = this.getFxEl();
10703         o = o || {};
10704         el.queueFx(o, function(){
10705             this.setOpacity(0);
10706             this.fixDisplay();
10707             this.dom.style.visibility = 'visible';
10708             var to = o.endOpacity || 1;
10709             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10710                 o, null, .5, "easeOut", function(){
10711                 if(to == 1){
10712                     this.clearOpacity();
10713                 }
10714                 el.afterFx(o);
10715             });
10716         });
10717         return this;
10718     },
10719
10720    /**
10721     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10722     * using the "endOpacity" config option.
10723     * Usage:
10724 <pre><code>
10725 // default: fade out from the element's current opacity to 0
10726 el.fadeOut();
10727
10728 // custom: fade out from the element's current opacity to 25% over 2 seconds
10729 el.fadeOut({ endOpacity: .25, duration: 2});
10730
10731 // common config options shown with default values
10732 el.fadeOut({
10733     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10734     easing: 'easeOut',
10735     duration: .5
10736     remove: false,
10737     useDisplay: false
10738 });
10739 </code></pre>
10740     * @param {Object} options (optional) Object literal with any of the Fx config options
10741     * @return {Roo.Element} The Element
10742     */
10743     fadeOut : function(o){
10744         var el = this.getFxEl();
10745         o = o || {};
10746         el.queueFx(o, function(){
10747             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10748                 o, null, .5, "easeOut", function(){
10749                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10750                      this.dom.style.display = "none";
10751                 }else{
10752                      this.dom.style.visibility = "hidden";
10753                 }
10754                 this.clearOpacity();
10755                 el.afterFx(o);
10756             });
10757         });
10758         return this;
10759     },
10760
10761    /**
10762     * Animates the transition of an element's dimensions from a starting height/width
10763     * to an ending height/width.
10764     * Usage:
10765 <pre><code>
10766 // change height and width to 100x100 pixels
10767 el.scale(100, 100);
10768
10769 // common config options shown with default values.  The height and width will default to
10770 // the element's existing values if passed as null.
10771 el.scale(
10772     [element's width],
10773     [element's height], {
10774     easing: 'easeOut',
10775     duration: .35
10776 });
10777 </code></pre>
10778     * @param {Number} width  The new width (pass undefined to keep the original width)
10779     * @param {Number} height  The new height (pass undefined to keep the original height)
10780     * @param {Object} options (optional) Object literal with any of the Fx config options
10781     * @return {Roo.Element} The Element
10782     */
10783     scale : function(w, h, o){
10784         this.shift(Roo.apply({}, o, {
10785             width: w,
10786             height: h
10787         }));
10788         return this;
10789     },
10790
10791    /**
10792     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10793     * Any of these properties not specified in the config object will not be changed.  This effect 
10794     * requires that at least one new dimension, position or opacity setting must be passed in on
10795     * the config object in order for the function to have any effect.
10796     * Usage:
10797 <pre><code>
10798 // slide the element horizontally to x position 200 while changing the height and opacity
10799 el.shift({ x: 200, height: 50, opacity: .8 });
10800
10801 // common config options shown with default values.
10802 el.shift({
10803     width: [element's width],
10804     height: [element's height],
10805     x: [element's x position],
10806     y: [element's y position],
10807     opacity: [element's opacity],
10808     easing: 'easeOut',
10809     duration: .35
10810 });
10811 </code></pre>
10812     * @param {Object} options  Object literal with any of the Fx config options
10813     * @return {Roo.Element} The Element
10814     */
10815     shift : function(o){
10816         var el = this.getFxEl();
10817         o = o || {};
10818         el.queueFx(o, function(){
10819             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10820             if(w !== undefined){
10821                 a.width = {to: this.adjustWidth(w)};
10822             }
10823             if(h !== undefined){
10824                 a.height = {to: this.adjustHeight(h)};
10825             }
10826             if(x !== undefined || y !== undefined){
10827                 a.points = {to: [
10828                     x !== undefined ? x : this.getX(),
10829                     y !== undefined ? y : this.getY()
10830                 ]};
10831             }
10832             if(op !== undefined){
10833                 a.opacity = {to: op};
10834             }
10835             if(o.xy !== undefined){
10836                 a.points = {to: o.xy};
10837             }
10838             arguments.callee.anim = this.fxanim(a,
10839                 o, 'motion', .35, "easeOut", function(){
10840                 el.afterFx(o);
10841             });
10842         });
10843         return this;
10844     },
10845
10846         /**
10847          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10848          * ending point of the effect.
10849          * Usage:
10850          *<pre><code>
10851 // default: slide the element downward while fading out
10852 el.ghost();
10853
10854 // custom: slide the element out to the right with a 2-second duration
10855 el.ghost('r', { duration: 2 });
10856
10857 // common config options shown with default values
10858 el.ghost('b', {
10859     easing: 'easeOut',
10860     duration: .5
10861     remove: false,
10862     useDisplay: false
10863 });
10864 </code></pre>
10865          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10866          * @param {Object} options (optional) Object literal with any of the Fx config options
10867          * @return {Roo.Element} The Element
10868          */
10869     ghost : function(anchor, o){
10870         var el = this.getFxEl();
10871         o = o || {};
10872
10873         el.queueFx(o, function(){
10874             anchor = anchor || "b";
10875
10876             // restore values after effect
10877             var r = this.getFxRestore();
10878             var w = this.getWidth(),
10879                 h = this.getHeight();
10880
10881             var st = this.dom.style;
10882
10883             var after = function(){
10884                 if(o.useDisplay){
10885                     el.setDisplayed(false);
10886                 }else{
10887                     el.hide();
10888                 }
10889
10890                 el.clearOpacity();
10891                 el.setPositioning(r.pos);
10892                 st.width = r.width;
10893                 st.height = r.height;
10894
10895                 el.afterFx(o);
10896             };
10897
10898             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10899             switch(anchor.toLowerCase()){
10900                 case "t":
10901                     pt.by = [0, -h];
10902                 break;
10903                 case "l":
10904                     pt.by = [-w, 0];
10905                 break;
10906                 case "r":
10907                     pt.by = [w, 0];
10908                 break;
10909                 case "b":
10910                     pt.by = [0, h];
10911                 break;
10912                 case "tl":
10913                     pt.by = [-w, -h];
10914                 break;
10915                 case "bl":
10916                     pt.by = [-w, h];
10917                 break;
10918                 case "br":
10919                     pt.by = [w, h];
10920                 break;
10921                 case "tr":
10922                     pt.by = [w, -h];
10923                 break;
10924             }
10925
10926             arguments.callee.anim = this.fxanim(a,
10927                 o,
10928                 'motion',
10929                 .5,
10930                 "easeOut", after);
10931         });
10932         return this;
10933     },
10934
10935         /**
10936          * Ensures that all effects queued after syncFx is called on the element are
10937          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10938          * @return {Roo.Element} The Element
10939          */
10940     syncFx : function(){
10941         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10942             block : false,
10943             concurrent : true,
10944             stopFx : false
10945         });
10946         return this;
10947     },
10948
10949         /**
10950          * Ensures that all effects queued after sequenceFx is called on the element are
10951          * run in sequence.  This is the opposite of {@link #syncFx}.
10952          * @return {Roo.Element} The Element
10953          */
10954     sequenceFx : function(){
10955         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10956             block : false,
10957             concurrent : false,
10958             stopFx : false
10959         });
10960         return this;
10961     },
10962
10963         /* @private */
10964     nextFx : function(){
10965         var ef = this.fxQueue[0];
10966         if(ef){
10967             ef.call(this);
10968         }
10969     },
10970
10971         /**
10972          * Returns true if the element has any effects actively running or queued, else returns false.
10973          * @return {Boolean} True if element has active effects, else false
10974          */
10975     hasActiveFx : function(){
10976         return this.fxQueue && this.fxQueue[0];
10977     },
10978
10979         /**
10980          * Stops any running effects and clears the element's internal effects queue if it contains
10981          * any additional effects that haven't started yet.
10982          * @return {Roo.Element} The Element
10983          */
10984     stopFx : function(){
10985         if(this.hasActiveFx()){
10986             var cur = this.fxQueue[0];
10987             if(cur && cur.anim && cur.anim.isAnimated()){
10988                 this.fxQueue = [cur]; // clear out others
10989                 cur.anim.stop(true);
10990             }
10991         }
10992         return this;
10993     },
10994
10995         /* @private */
10996     beforeFx : function(o){
10997         if(this.hasActiveFx() && !o.concurrent){
10998            if(o.stopFx){
10999                this.stopFx();
11000                return true;
11001            }
11002            return false;
11003         }
11004         return true;
11005     },
11006
11007         /**
11008          * Returns true if the element is currently blocking so that no other effect can be queued
11009          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11010          * used to ensure that an effect initiated by a user action runs to completion prior to the
11011          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11012          * @return {Boolean} True if blocking, else false
11013          */
11014     hasFxBlock : function(){
11015         var q = this.fxQueue;
11016         return q && q[0] && q[0].block;
11017     },
11018
11019         /* @private */
11020     queueFx : function(o, fn){
11021         if(!this.fxQueue){
11022             this.fxQueue = [];
11023         }
11024         if(!this.hasFxBlock()){
11025             Roo.applyIf(o, this.fxDefaults);
11026             if(!o.concurrent){
11027                 var run = this.beforeFx(o);
11028                 fn.block = o.block;
11029                 this.fxQueue.push(fn);
11030                 if(run){
11031                     this.nextFx();
11032                 }
11033             }else{
11034                 fn.call(this);
11035             }
11036         }
11037         return this;
11038     },
11039
11040         /* @private */
11041     fxWrap : function(pos, o, vis){
11042         var wrap;
11043         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11044             var wrapXY;
11045             if(o.fixPosition){
11046                 wrapXY = this.getXY();
11047             }
11048             var div = document.createElement("div");
11049             div.style.visibility = vis;
11050             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11051             wrap.setPositioning(pos);
11052             if(wrap.getStyle("position") == "static"){
11053                 wrap.position("relative");
11054             }
11055             this.clearPositioning('auto');
11056             wrap.clip();
11057             wrap.dom.appendChild(this.dom);
11058             if(wrapXY){
11059                 wrap.setXY(wrapXY);
11060             }
11061         }
11062         return wrap;
11063     },
11064
11065         /* @private */
11066     fxUnwrap : function(wrap, pos, o){
11067         this.clearPositioning();
11068         this.setPositioning(pos);
11069         if(!o.wrap){
11070             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11071             wrap.remove();
11072         }
11073     },
11074
11075         /* @private */
11076     getFxRestore : function(){
11077         var st = this.dom.style;
11078         return {pos: this.getPositioning(), width: st.width, height : st.height};
11079     },
11080
11081         /* @private */
11082     afterFx : function(o){
11083         if(o.afterStyle){
11084             this.applyStyles(o.afterStyle);
11085         }
11086         if(o.afterCls){
11087             this.addClass(o.afterCls);
11088         }
11089         if(o.remove === true){
11090             this.remove();
11091         }
11092         Roo.callback(o.callback, o.scope, [this]);
11093         if(!o.concurrent){
11094             this.fxQueue.shift();
11095             this.nextFx();
11096         }
11097     },
11098
11099         /* @private */
11100     getFxEl : function(){ // support for composite element fx
11101         return Roo.get(this.dom);
11102     },
11103
11104         /* @private */
11105     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11106         animType = animType || 'run';
11107         opt = opt || {};
11108         var anim = Roo.lib.Anim[animType](
11109             this.dom, args,
11110             (opt.duration || defaultDur) || .35,
11111             (opt.easing || defaultEase) || 'easeOut',
11112             function(){
11113                 Roo.callback(cb, this);
11114             },
11115             this
11116         );
11117         opt.anim = anim;
11118         return anim;
11119     }
11120 };
11121
11122 // backwords compat
11123 Roo.Fx.resize = Roo.Fx.scale;
11124
11125 //When included, Roo.Fx is automatically applied to Element so that all basic
11126 //effects are available directly via the Element API
11127 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11128  * Based on:
11129  * Ext JS Library 1.1.1
11130  * Copyright(c) 2006-2007, Ext JS, LLC.
11131  *
11132  * Originally Released Under LGPL - original licence link has changed is not relivant.
11133  *
11134  * Fork - LGPL
11135  * <script type="text/javascript">
11136  */
11137
11138
11139 /**
11140  * @class Roo.CompositeElement
11141  * Standard composite class. Creates a Roo.Element for every element in the collection.
11142  * <br><br>
11143  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11144  * actions will be performed on all the elements in this collection.</b>
11145  * <br><br>
11146  * All methods return <i>this</i> and can be chained.
11147  <pre><code>
11148  var els = Roo.select("#some-el div.some-class", true);
11149  // or select directly from an existing element
11150  var el = Roo.get('some-el');
11151  el.select('div.some-class', true);
11152
11153  els.setWidth(100); // all elements become 100 width
11154  els.hide(true); // all elements fade out and hide
11155  // or
11156  els.setWidth(100).hide(true);
11157  </code></pre>
11158  */
11159 Roo.CompositeElement = function(els){
11160     this.elements = [];
11161     this.addElements(els);
11162 };
11163 Roo.CompositeElement.prototype = {
11164     isComposite: true,
11165     addElements : function(els){
11166         if(!els) {
11167             return this;
11168         }
11169         if(typeof els == "string"){
11170             els = Roo.Element.selectorFunction(els);
11171         }
11172         var yels = this.elements;
11173         var index = yels.length-1;
11174         for(var i = 0, len = els.length; i < len; i++) {
11175                 yels[++index] = Roo.get(els[i]);
11176         }
11177         return this;
11178     },
11179
11180     /**
11181     * Clears this composite and adds the elements returned by the passed selector.
11182     * @param {String/Array} els A string CSS selector, an array of elements or an element
11183     * @return {CompositeElement} this
11184     */
11185     fill : function(els){
11186         this.elements = [];
11187         this.add(els);
11188         return this;
11189     },
11190
11191     /**
11192     * Filters this composite to only elements that match the passed selector.
11193     * @param {String} selector A string CSS selector
11194     * @param {Boolean} inverse return inverse filter (not matches)
11195     * @return {CompositeElement} this
11196     */
11197     filter : function(selector, inverse){
11198         var els = [];
11199         inverse = inverse || false;
11200         this.each(function(el){
11201             var match = inverse ? !el.is(selector) : el.is(selector);
11202             if(match){
11203                 els[els.length] = el.dom;
11204             }
11205         });
11206         this.fill(els);
11207         return this;
11208     },
11209
11210     invoke : function(fn, args){
11211         var els = this.elements;
11212         for(var i = 0, len = els.length; i < len; i++) {
11213                 Roo.Element.prototype[fn].apply(els[i], args);
11214         }
11215         return this;
11216     },
11217     /**
11218     * Adds elements to this composite.
11219     * @param {String/Array} els A string CSS selector, an array of elements or an element
11220     * @return {CompositeElement} this
11221     */
11222     add : function(els){
11223         if(typeof els == "string"){
11224             this.addElements(Roo.Element.selectorFunction(els));
11225         }else if(els.length !== undefined){
11226             this.addElements(els);
11227         }else{
11228             this.addElements([els]);
11229         }
11230         return this;
11231     },
11232     /**
11233     * Calls the passed function passing (el, this, index) for each element in this composite.
11234     * @param {Function} fn The function to call
11235     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11236     * @return {CompositeElement} this
11237     */
11238     each : function(fn, scope){
11239         var els = this.elements;
11240         for(var i = 0, len = els.length; i < len; i++){
11241             if(fn.call(scope || els[i], els[i], this, i) === false) {
11242                 break;
11243             }
11244         }
11245         return this;
11246     },
11247
11248     /**
11249      * Returns the Element object at the specified index
11250      * @param {Number} index
11251      * @return {Roo.Element}
11252      */
11253     item : function(index){
11254         return this.elements[index] || null;
11255     },
11256
11257     /**
11258      * Returns the first Element
11259      * @return {Roo.Element}
11260      */
11261     first : function(){
11262         return this.item(0);
11263     },
11264
11265     /**
11266      * Returns the last Element
11267      * @return {Roo.Element}
11268      */
11269     last : function(){
11270         return this.item(this.elements.length-1);
11271     },
11272
11273     /**
11274      * Returns the number of elements in this composite
11275      * @return Number
11276      */
11277     getCount : function(){
11278         return this.elements.length;
11279     },
11280
11281     /**
11282      * Returns true if this composite contains the passed element
11283      * @return Boolean
11284      */
11285     contains : function(el){
11286         return this.indexOf(el) !== -1;
11287     },
11288
11289     /**
11290      * Returns true if this composite contains the passed element
11291      * @return Boolean
11292      */
11293     indexOf : function(el){
11294         return this.elements.indexOf(Roo.get(el));
11295     },
11296
11297
11298     /**
11299     * Removes the specified element(s).
11300     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11301     * or an array of any of those.
11302     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11303     * @return {CompositeElement} this
11304     */
11305     removeElement : function(el, removeDom){
11306         if(el instanceof Array){
11307             for(var i = 0, len = el.length; i < len; i++){
11308                 this.removeElement(el[i]);
11309             }
11310             return this;
11311         }
11312         var index = typeof el == 'number' ? el : this.indexOf(el);
11313         if(index !== -1){
11314             if(removeDom){
11315                 var d = this.elements[index];
11316                 if(d.dom){
11317                     d.remove();
11318                 }else{
11319                     d.parentNode.removeChild(d);
11320                 }
11321             }
11322             this.elements.splice(index, 1);
11323         }
11324         return this;
11325     },
11326
11327     /**
11328     * Replaces the specified element with the passed element.
11329     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11330     * to replace.
11331     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11332     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11333     * @return {CompositeElement} this
11334     */
11335     replaceElement : function(el, replacement, domReplace){
11336         var index = typeof el == 'number' ? el : this.indexOf(el);
11337         if(index !== -1){
11338             if(domReplace){
11339                 this.elements[index].replaceWith(replacement);
11340             }else{
11341                 this.elements.splice(index, 1, Roo.get(replacement))
11342             }
11343         }
11344         return this;
11345     },
11346
11347     /**
11348      * Removes all elements.
11349      */
11350     clear : function(){
11351         this.elements = [];
11352     }
11353 };
11354 (function(){
11355     Roo.CompositeElement.createCall = function(proto, fnName){
11356         if(!proto[fnName]){
11357             proto[fnName] = function(){
11358                 return this.invoke(fnName, arguments);
11359             };
11360         }
11361     };
11362     for(var fnName in Roo.Element.prototype){
11363         if(typeof Roo.Element.prototype[fnName] == "function"){
11364             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11365         }
11366     };
11367 })();
11368 /*
11369  * Based on:
11370  * Ext JS Library 1.1.1
11371  * Copyright(c) 2006-2007, Ext JS, LLC.
11372  *
11373  * Originally Released Under LGPL - original licence link has changed is not relivant.
11374  *
11375  * Fork - LGPL
11376  * <script type="text/javascript">
11377  */
11378
11379 /**
11380  * @class Roo.CompositeElementLite
11381  * @extends Roo.CompositeElement
11382  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11383  <pre><code>
11384  var els = Roo.select("#some-el div.some-class");
11385  // or select directly from an existing element
11386  var el = Roo.get('some-el');
11387  el.select('div.some-class');
11388
11389  els.setWidth(100); // all elements become 100 width
11390  els.hide(true); // all elements fade out and hide
11391  // or
11392  els.setWidth(100).hide(true);
11393  </code></pre><br><br>
11394  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11395  * actions will be performed on all the elements in this collection.</b>
11396  */
11397 Roo.CompositeElementLite = function(els){
11398     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11399     this.el = new Roo.Element.Flyweight();
11400 };
11401 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11402     addElements : function(els){
11403         if(els){
11404             if(els instanceof Array){
11405                 this.elements = this.elements.concat(els);
11406             }else{
11407                 var yels = this.elements;
11408                 var index = yels.length-1;
11409                 for(var i = 0, len = els.length; i < len; i++) {
11410                     yels[++index] = els[i];
11411                 }
11412             }
11413         }
11414         return this;
11415     },
11416     invoke : function(fn, args){
11417         var els = this.elements;
11418         var el = this.el;
11419         for(var i = 0, len = els.length; i < len; i++) {
11420             el.dom = els[i];
11421                 Roo.Element.prototype[fn].apply(el, args);
11422         }
11423         return this;
11424     },
11425     /**
11426      * Returns a flyweight Element of the dom element object at the specified index
11427      * @param {Number} index
11428      * @return {Roo.Element}
11429      */
11430     item : function(index){
11431         if(!this.elements[index]){
11432             return null;
11433         }
11434         this.el.dom = this.elements[index];
11435         return this.el;
11436     },
11437
11438     // fixes scope with flyweight
11439     addListener : function(eventName, handler, scope, opt){
11440         var els = this.elements;
11441         for(var i = 0, len = els.length; i < len; i++) {
11442             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11443         }
11444         return this;
11445     },
11446
11447     /**
11448     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11449     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11450     * a reference to the dom node, use el.dom.</b>
11451     * @param {Function} fn The function to call
11452     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11453     * @return {CompositeElement} this
11454     */
11455     each : function(fn, scope){
11456         var els = this.elements;
11457         var el = this.el;
11458         for(var i = 0, len = els.length; i < len; i++){
11459             el.dom = els[i];
11460                 if(fn.call(scope || el, el, this, i) === false){
11461                 break;
11462             }
11463         }
11464         return this;
11465     },
11466
11467     indexOf : function(el){
11468         return this.elements.indexOf(Roo.getDom(el));
11469     },
11470
11471     replaceElement : function(el, replacement, domReplace){
11472         var index = typeof el == 'number' ? el : this.indexOf(el);
11473         if(index !== -1){
11474             replacement = Roo.getDom(replacement);
11475             if(domReplace){
11476                 var d = this.elements[index];
11477                 d.parentNode.insertBefore(replacement, d);
11478                 d.parentNode.removeChild(d);
11479             }
11480             this.elements.splice(index, 1, replacement);
11481         }
11482         return this;
11483     }
11484 });
11485 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11486
11487 /*
11488  * Based on:
11489  * Ext JS Library 1.1.1
11490  * Copyright(c) 2006-2007, Ext JS, LLC.
11491  *
11492  * Originally Released Under LGPL - original licence link has changed is not relivant.
11493  *
11494  * Fork - LGPL
11495  * <script type="text/javascript">
11496  */
11497
11498  
11499
11500 /**
11501  * @class Roo.data.Connection
11502  * @extends Roo.util.Observable
11503  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11504  * either to a configured URL, or to a URL specified at request time. 
11505  * 
11506  * Requests made by this class are asynchronous, and will return immediately. No data from
11507  * the server will be available to the statement immediately following the {@link #request} call.
11508  * To process returned data, use a callback in the request options object, or an event listener.
11509  * 
11510  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11511  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11512  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11513  * property and, if present, the IFRAME's XML document as the responseXML property.
11514  * 
11515  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11516  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11517  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11518  * standard DOM methods.
11519  * @constructor
11520  * @param {Object} config a configuration object.
11521  */
11522 Roo.data.Connection = function(config){
11523     Roo.apply(this, config);
11524     this.addEvents({
11525         /**
11526          * @event beforerequest
11527          * Fires before a network request is made to retrieve a data object.
11528          * @param {Connection} conn This Connection object.
11529          * @param {Object} options The options config object passed to the {@link #request} method.
11530          */
11531         "beforerequest" : true,
11532         /**
11533          * @event requestcomplete
11534          * Fires if the request was successfully completed.
11535          * @param {Connection} conn This Connection object.
11536          * @param {Object} response The XHR object containing the response data.
11537          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11538          * @param {Object} options The options config object passed to the {@link #request} method.
11539          */
11540         "requestcomplete" : true,
11541         /**
11542          * @event requestexception
11543          * Fires if an error HTTP status was returned from the server.
11544          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11545          * @param {Connection} conn This Connection object.
11546          * @param {Object} response The XHR object containing the response data.
11547          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11548          * @param {Object} options The options config object passed to the {@link #request} method.
11549          */
11550         "requestexception" : true
11551     });
11552     Roo.data.Connection.superclass.constructor.call(this);
11553 };
11554
11555 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11556     /**
11557      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11558      */
11559     /**
11560      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11561      * extra parameters to each request made by this object. (defaults to undefined)
11562      */
11563     /**
11564      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11565      *  to each request made by this object. (defaults to undefined)
11566      */
11567     /**
11568      * @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)
11569      */
11570     /**
11571      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11572      */
11573     timeout : 30000,
11574     /**
11575      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11576      * @type Boolean
11577      */
11578     autoAbort:false,
11579
11580     /**
11581      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11582      * @type Boolean
11583      */
11584     disableCaching: true,
11585
11586     /**
11587      * Sends an HTTP request to a remote server.
11588      * @param {Object} options An object which may contain the following properties:<ul>
11589      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11590      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11591      * request, a url encoded string or a function to call to get either.</li>
11592      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11593      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11594      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11595      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11596      * <li>options {Object} The parameter to the request call.</li>
11597      * <li>success {Boolean} True if the request succeeded.</li>
11598      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11599      * </ul></li>
11600      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11601      * The callback is passed the following parameters:<ul>
11602      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11603      * <li>options {Object} The parameter to the request call.</li>
11604      * </ul></li>
11605      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11606      * The callback is passed the following parameters:<ul>
11607      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11608      * <li>options {Object} The parameter to the request call.</li>
11609      * </ul></li>
11610      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11611      * for the callback function. Defaults to the browser window.</li>
11612      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11613      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11614      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11615      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11616      * params for the post data. Any params will be appended to the URL.</li>
11617      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11618      * </ul>
11619      * @return {Number} transactionId
11620      */
11621     request : function(o){
11622         if(this.fireEvent("beforerequest", this, o) !== false){
11623             var p = o.params;
11624
11625             if(typeof p == "function"){
11626                 p = p.call(o.scope||window, o);
11627             }
11628             if(typeof p == "object"){
11629                 p = Roo.urlEncode(o.params);
11630             }
11631             if(this.extraParams){
11632                 var extras = Roo.urlEncode(this.extraParams);
11633                 p = p ? (p + '&' + extras) : extras;
11634             }
11635
11636             var url = o.url || this.url;
11637             if(typeof url == 'function'){
11638                 url = url.call(o.scope||window, o);
11639             }
11640
11641             if(o.form){
11642                 var form = Roo.getDom(o.form);
11643                 url = url || form.action;
11644
11645                 var enctype = form.getAttribute("enctype");
11646                 
11647                 if (o.formData) {
11648                     return this.doFormDataUpload(o, url);
11649                 }
11650                 
11651                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11652                     return this.doFormUpload(o, p, url);
11653                 }
11654                 var f = Roo.lib.Ajax.serializeForm(form);
11655                 p = p ? (p + '&' + f) : f;
11656             }
11657             
11658             if (!o.form && o.formData) {
11659                 o.formData = o.formData === true ? new FormData() : o.formData;
11660                 for (var k in o.params) {
11661                     o.formData.append(k,o.params[k]);
11662                 }
11663                     
11664                 return this.doFormDataUpload(o, url);
11665             }
11666             
11667
11668             var hs = o.headers;
11669             if(this.defaultHeaders){
11670                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11671                 if(!o.headers){
11672                     o.headers = hs;
11673                 }
11674             }
11675
11676             var cb = {
11677                 success: this.handleResponse,
11678                 failure: this.handleFailure,
11679                 scope: this,
11680                 argument: {options: o},
11681                 timeout : o.timeout || this.timeout
11682             };
11683
11684             var method = o.method||this.method||(p ? "POST" : "GET");
11685
11686             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11687                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11688             }
11689
11690             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11691                 if(o.autoAbort){
11692                     this.abort();
11693                 }
11694             }else if(this.autoAbort !== false){
11695                 this.abort();
11696             }
11697
11698             if((method == 'GET' && p) || o.xmlData){
11699                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11700                 p = '';
11701             }
11702             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11703             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11704             Roo.lib.Ajax.useDefaultHeader == true;
11705             return this.transId;
11706         }else{
11707             Roo.callback(o.callback, o.scope, [o, null, null]);
11708             return null;
11709         }
11710     },
11711
11712     /**
11713      * Determine whether this object has a request outstanding.
11714      * @param {Number} transactionId (Optional) defaults to the last transaction
11715      * @return {Boolean} True if there is an outstanding request.
11716      */
11717     isLoading : function(transId){
11718         if(transId){
11719             return Roo.lib.Ajax.isCallInProgress(transId);
11720         }else{
11721             return this.transId ? true : false;
11722         }
11723     },
11724
11725     /**
11726      * Aborts any outstanding request.
11727      * @param {Number} transactionId (Optional) defaults to the last transaction
11728      */
11729     abort : function(transId){
11730         if(transId || this.isLoading()){
11731             Roo.lib.Ajax.abort(transId || this.transId);
11732         }
11733     },
11734
11735     // private
11736     handleResponse : function(response){
11737         this.transId = false;
11738         var options = response.argument.options;
11739         response.argument = options ? options.argument : null;
11740         this.fireEvent("requestcomplete", this, response, options);
11741         Roo.callback(options.success, options.scope, [response, options]);
11742         Roo.callback(options.callback, options.scope, [options, true, response]);
11743     },
11744
11745     // private
11746     handleFailure : function(response, e){
11747         this.transId = false;
11748         var options = response.argument.options;
11749         response.argument = options ? options.argument : null;
11750         this.fireEvent("requestexception", this, response, options, e);
11751         Roo.callback(options.failure, options.scope, [response, options]);
11752         Roo.callback(options.callback, options.scope, [options, false, response]);
11753     },
11754
11755     // private
11756     doFormUpload : function(o, ps, url){
11757         var id = Roo.id();
11758         var frame = document.createElement('iframe');
11759         frame.id = id;
11760         frame.name = id;
11761         frame.className = 'x-hidden';
11762         if(Roo.isIE){
11763             frame.src = Roo.SSL_SECURE_URL;
11764         }
11765         document.body.appendChild(frame);
11766
11767         if(Roo.isIE){
11768            document.frames[id].name = id;
11769         }
11770
11771         var form = Roo.getDom(o.form);
11772         form.target = id;
11773         form.method = 'POST';
11774         form.enctype = form.encoding = 'multipart/form-data';
11775         if(url){
11776             form.action = url;
11777         }
11778
11779         var hiddens, hd;
11780         if(ps){ // add dynamic params
11781             hiddens = [];
11782             ps = Roo.urlDecode(ps, false);
11783             for(var k in ps){
11784                 if(ps.hasOwnProperty(k)){
11785                     hd = document.createElement('input');
11786                     hd.type = 'hidden';
11787                     hd.name = k;
11788                     hd.value = ps[k];
11789                     form.appendChild(hd);
11790                     hiddens.push(hd);
11791                 }
11792             }
11793         }
11794
11795         function cb(){
11796             var r = {  // bogus response object
11797                 responseText : '',
11798                 responseXML : null
11799             };
11800
11801             r.argument = o ? o.argument : null;
11802
11803             try { //
11804                 var doc;
11805                 if(Roo.isIE){
11806                     doc = frame.contentWindow.document;
11807                 }else {
11808                     doc = (frame.contentDocument || window.frames[id].document);
11809                 }
11810                 if(doc && doc.body){
11811                     r.responseText = doc.body.innerHTML;
11812                 }
11813                 if(doc && doc.XMLDocument){
11814                     r.responseXML = doc.XMLDocument;
11815                 }else {
11816                     r.responseXML = doc;
11817                 }
11818             }
11819             catch(e) {
11820                 // ignore
11821             }
11822
11823             Roo.EventManager.removeListener(frame, 'load', cb, this);
11824
11825             this.fireEvent("requestcomplete", this, r, o);
11826             Roo.callback(o.success, o.scope, [r, o]);
11827             Roo.callback(o.callback, o.scope, [o, true, r]);
11828
11829             setTimeout(function(){document.body.removeChild(frame);}, 100);
11830         }
11831
11832         Roo.EventManager.on(frame, 'load', cb, this);
11833         form.submit();
11834
11835         if(hiddens){ // remove dynamic params
11836             for(var i = 0, len = hiddens.length; i < len; i++){
11837                 form.removeChild(hiddens[i]);
11838             }
11839         }
11840     },
11841     // this is a 'formdata version???'
11842     
11843     
11844     doFormDataUpload : function(o,  url)
11845     {
11846         var formData;
11847         if (o.form) {
11848             var form =  Roo.getDom(o.form);
11849             form.enctype = form.encoding = 'multipart/form-data';
11850             formData = o.formData === true ? new FormData(form) : o.formData;
11851         } else {
11852             formData = o.formData === true ? new FormData() : o.formData;
11853         }
11854         
11855       
11856         var cb = {
11857             success: this.handleResponse,
11858             failure: this.handleFailure,
11859             scope: this,
11860             argument: {options: o},
11861             timeout : o.timeout || this.timeout
11862         };
11863  
11864         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11865             if(o.autoAbort){
11866                 this.abort();
11867             }
11868         }else if(this.autoAbort !== false){
11869             this.abort();
11870         }
11871
11872         //Roo.lib.Ajax.defaultPostHeader = null;
11873         Roo.lib.Ajax.useDefaultHeader = false;
11874         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
11875         Roo.lib.Ajax.useDefaultHeader = true;
11876  
11877          
11878     }
11879     
11880 });
11881 /*
11882  * Based on:
11883  * Ext JS Library 1.1.1
11884  * Copyright(c) 2006-2007, Ext JS, LLC.
11885  *
11886  * Originally Released Under LGPL - original licence link has changed is not relivant.
11887  *
11888  * Fork - LGPL
11889  * <script type="text/javascript">
11890  */
11891  
11892 /**
11893  * Global Ajax request class.
11894  * 
11895  * @class Roo.Ajax
11896  * @extends Roo.data.Connection
11897  * @static
11898  * 
11899  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11900  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11901  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11902  * @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)
11903  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11904  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11905  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11906  */
11907 Roo.Ajax = new Roo.data.Connection({
11908     // fix up the docs
11909     /**
11910      * @scope Roo.Ajax
11911      * @type {Boolear} 
11912      */
11913     autoAbort : false,
11914
11915     /**
11916      * Serialize the passed form into a url encoded string
11917      * @scope Roo.Ajax
11918      * @param {String/HTMLElement} form
11919      * @return {String}
11920      */
11921     serializeForm : function(form){
11922         return Roo.lib.Ajax.serializeForm(form);
11923     }
11924 });/*
11925  * Based on:
11926  * Ext JS Library 1.1.1
11927  * Copyright(c) 2006-2007, Ext JS, LLC.
11928  *
11929  * Originally Released Under LGPL - original licence link has changed is not relivant.
11930  *
11931  * Fork - LGPL
11932  * <script type="text/javascript">
11933  */
11934
11935  
11936 /**
11937  * @class Roo.UpdateManager
11938  * @extends Roo.util.Observable
11939  * Provides AJAX-style update for Element object.<br><br>
11940  * Usage:<br>
11941  * <pre><code>
11942  * // Get it from a Roo.Element object
11943  * var el = Roo.get("foo");
11944  * var mgr = el.getUpdateManager();
11945  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11946  * ...
11947  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11948  * <br>
11949  * // or directly (returns the same UpdateManager instance)
11950  * var mgr = new Roo.UpdateManager("myElementId");
11951  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11952  * mgr.on("update", myFcnNeedsToKnow);
11953  * <br>
11954    // short handed call directly from the element object
11955    Roo.get("foo").load({
11956         url: "bar.php",
11957         scripts:true,
11958         params: "for=bar",
11959         text: "Loading Foo..."
11960    });
11961  * </code></pre>
11962  * @constructor
11963  * Create new UpdateManager directly.
11964  * @param {String/HTMLElement/Roo.Element} el The element to update
11965  * @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).
11966  */
11967 Roo.UpdateManager = function(el, forceNew){
11968     el = Roo.get(el);
11969     if(!forceNew && el.updateManager){
11970         return el.updateManager;
11971     }
11972     /**
11973      * The Element object
11974      * @type Roo.Element
11975      */
11976     this.el = el;
11977     /**
11978      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11979      * @type String
11980      */
11981     this.defaultUrl = null;
11982
11983     this.addEvents({
11984         /**
11985          * @event beforeupdate
11986          * Fired before an update is made, return false from your handler and the update is cancelled.
11987          * @param {Roo.Element} el
11988          * @param {String/Object/Function} url
11989          * @param {String/Object} params
11990          */
11991         "beforeupdate": true,
11992         /**
11993          * @event update
11994          * Fired after successful update is made.
11995          * @param {Roo.Element} el
11996          * @param {Object} oResponseObject The response Object
11997          */
11998         "update": true,
11999         /**
12000          * @event failure
12001          * Fired on update failure.
12002          * @param {Roo.Element} el
12003          * @param {Object} oResponseObject The response Object
12004          */
12005         "failure": true
12006     });
12007     var d = Roo.UpdateManager.defaults;
12008     /**
12009      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12010      * @type String
12011      */
12012     this.sslBlankUrl = d.sslBlankUrl;
12013     /**
12014      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12015      * @type Boolean
12016      */
12017     this.disableCaching = d.disableCaching;
12018     /**
12019      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12020      * @type String
12021      */
12022     this.indicatorText = d.indicatorText;
12023     /**
12024      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12025      * @type String
12026      */
12027     this.showLoadIndicator = d.showLoadIndicator;
12028     /**
12029      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12030      * @type Number
12031      */
12032     this.timeout = d.timeout;
12033
12034     /**
12035      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12036      * @type Boolean
12037      */
12038     this.loadScripts = d.loadScripts;
12039
12040     /**
12041      * Transaction object of current executing transaction
12042      */
12043     this.transaction = null;
12044
12045     /**
12046      * @private
12047      */
12048     this.autoRefreshProcId = null;
12049     /**
12050      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12051      * @type Function
12052      */
12053     this.refreshDelegate = this.refresh.createDelegate(this);
12054     /**
12055      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12056      * @type Function
12057      */
12058     this.updateDelegate = this.update.createDelegate(this);
12059     /**
12060      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12061      * @type Function
12062      */
12063     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12064     /**
12065      * @private
12066      */
12067     this.successDelegate = this.processSuccess.createDelegate(this);
12068     /**
12069      * @private
12070      */
12071     this.failureDelegate = this.processFailure.createDelegate(this);
12072
12073     if(!this.renderer){
12074      /**
12075       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12076       */
12077     this.renderer = new Roo.UpdateManager.BasicRenderer();
12078     }
12079     
12080     Roo.UpdateManager.superclass.constructor.call(this);
12081 };
12082
12083 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12084     /**
12085      * Get the Element this UpdateManager is bound to
12086      * @return {Roo.Element} The element
12087      */
12088     getEl : function(){
12089         return this.el;
12090     },
12091     /**
12092      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12093      * @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:
12094 <pre><code>
12095 um.update({<br/>
12096     url: "your-url.php",<br/>
12097     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12098     callback: yourFunction,<br/>
12099     scope: yourObject, //(optional scope)  <br/>
12100     discardUrl: false, <br/>
12101     nocache: false,<br/>
12102     text: "Loading...",<br/>
12103     timeout: 30,<br/>
12104     scripts: false<br/>
12105 });
12106 </code></pre>
12107      * The only required property is url. The optional properties nocache, text and scripts
12108      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12109      * @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}
12110      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12111      * @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.
12112      */
12113     update : function(url, params, callback, discardUrl){
12114         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12115             var method = this.method,
12116                 cfg;
12117             if(typeof url == "object"){ // must be config object
12118                 cfg = url;
12119                 url = cfg.url;
12120                 params = params || cfg.params;
12121                 callback = callback || cfg.callback;
12122                 discardUrl = discardUrl || cfg.discardUrl;
12123                 if(callback && cfg.scope){
12124                     callback = callback.createDelegate(cfg.scope);
12125                 }
12126                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12127                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12128                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12129                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12130                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12131             }
12132             this.showLoading();
12133             if(!discardUrl){
12134                 this.defaultUrl = url;
12135             }
12136             if(typeof url == "function"){
12137                 url = url.call(this);
12138             }
12139
12140             method = method || (params ? "POST" : "GET");
12141             if(method == "GET"){
12142                 url = this.prepareUrl(url);
12143             }
12144
12145             var o = Roo.apply(cfg ||{}, {
12146                 url : url,
12147                 params: params,
12148                 success: this.successDelegate,
12149                 failure: this.failureDelegate,
12150                 callback: undefined,
12151                 timeout: (this.timeout*1000),
12152                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12153             });
12154             Roo.log("updated manager called with timeout of " + o.timeout);
12155             this.transaction = Roo.Ajax.request(o);
12156         }
12157     },
12158
12159     /**
12160      * 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.
12161      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12162      * @param {String/HTMLElement} form The form Id or form element
12163      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12164      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12165      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12166      */
12167     formUpdate : function(form, url, reset, callback){
12168         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12169             if(typeof url == "function"){
12170                 url = url.call(this);
12171             }
12172             form = Roo.getDom(form);
12173             this.transaction = Roo.Ajax.request({
12174                 form: form,
12175                 url:url,
12176                 success: this.successDelegate,
12177                 failure: this.failureDelegate,
12178                 timeout: (this.timeout*1000),
12179                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12180             });
12181             this.showLoading.defer(1, this);
12182         }
12183     },
12184
12185     /**
12186      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12187      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12188      */
12189     refresh : function(callback){
12190         if(this.defaultUrl == null){
12191             return;
12192         }
12193         this.update(this.defaultUrl, null, callback, true);
12194     },
12195
12196     /**
12197      * Set this element to auto refresh.
12198      * @param {Number} interval How often to update (in seconds).
12199      * @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)
12200      * @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}
12201      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12202      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12203      */
12204     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12205         if(refreshNow){
12206             this.update(url || this.defaultUrl, params, callback, true);
12207         }
12208         if(this.autoRefreshProcId){
12209             clearInterval(this.autoRefreshProcId);
12210         }
12211         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12212     },
12213
12214     /**
12215      * Stop auto refresh on this element.
12216      */
12217      stopAutoRefresh : function(){
12218         if(this.autoRefreshProcId){
12219             clearInterval(this.autoRefreshProcId);
12220             delete this.autoRefreshProcId;
12221         }
12222     },
12223
12224     isAutoRefreshing : function(){
12225        return this.autoRefreshProcId ? true : false;
12226     },
12227     /**
12228      * Called to update the element to "Loading" state. Override to perform custom action.
12229      */
12230     showLoading : function(){
12231         if(this.showLoadIndicator){
12232             this.el.update(this.indicatorText);
12233         }
12234     },
12235
12236     /**
12237      * Adds unique parameter to query string if disableCaching = true
12238      * @private
12239      */
12240     prepareUrl : function(url){
12241         if(this.disableCaching){
12242             var append = "_dc=" + (new Date().getTime());
12243             if(url.indexOf("?") !== -1){
12244                 url += "&" + append;
12245             }else{
12246                 url += "?" + append;
12247             }
12248         }
12249         return url;
12250     },
12251
12252     /**
12253      * @private
12254      */
12255     processSuccess : function(response){
12256         this.transaction = null;
12257         if(response.argument.form && response.argument.reset){
12258             try{ // put in try/catch since some older FF releases had problems with this
12259                 response.argument.form.reset();
12260             }catch(e){}
12261         }
12262         if(this.loadScripts){
12263             this.renderer.render(this.el, response, this,
12264                 this.updateComplete.createDelegate(this, [response]));
12265         }else{
12266             this.renderer.render(this.el, response, this);
12267             this.updateComplete(response);
12268         }
12269     },
12270
12271     updateComplete : function(response){
12272         this.fireEvent("update", this.el, response);
12273         if(typeof response.argument.callback == "function"){
12274             response.argument.callback(this.el, true, response);
12275         }
12276     },
12277
12278     /**
12279      * @private
12280      */
12281     processFailure : function(response){
12282         this.transaction = null;
12283         this.fireEvent("failure", this.el, response);
12284         if(typeof response.argument.callback == "function"){
12285             response.argument.callback(this.el, false, response);
12286         }
12287     },
12288
12289     /**
12290      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12291      * @param {Object} renderer The object implementing the render() method
12292      */
12293     setRenderer : function(renderer){
12294         this.renderer = renderer;
12295     },
12296
12297     getRenderer : function(){
12298        return this.renderer;
12299     },
12300
12301     /**
12302      * Set the defaultUrl used for updates
12303      * @param {String/Function} defaultUrl The url or a function to call to get the url
12304      */
12305     setDefaultUrl : function(defaultUrl){
12306         this.defaultUrl = defaultUrl;
12307     },
12308
12309     /**
12310      * Aborts the executing transaction
12311      */
12312     abort : function(){
12313         if(this.transaction){
12314             Roo.Ajax.abort(this.transaction);
12315         }
12316     },
12317
12318     /**
12319      * Returns true if an update is in progress
12320      * @return {Boolean}
12321      */
12322     isUpdating : function(){
12323         if(this.transaction){
12324             return Roo.Ajax.isLoading(this.transaction);
12325         }
12326         return false;
12327     }
12328 });
12329
12330 /**
12331  * @class Roo.UpdateManager.defaults
12332  * @static (not really - but it helps the doc tool)
12333  * The defaults collection enables customizing the default properties of UpdateManager
12334  */
12335    Roo.UpdateManager.defaults = {
12336        /**
12337          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12338          * @type Number
12339          */
12340          timeout : 30,
12341
12342          /**
12343          * True to process scripts by default (Defaults to false).
12344          * @type Boolean
12345          */
12346         loadScripts : false,
12347
12348         /**
12349         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12350         * @type String
12351         */
12352         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12353         /**
12354          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12355          * @type Boolean
12356          */
12357         disableCaching : false,
12358         /**
12359          * Whether to show indicatorText when loading (Defaults to true).
12360          * @type Boolean
12361          */
12362         showLoadIndicator : true,
12363         /**
12364          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12365          * @type String
12366          */
12367         indicatorText : '<div class="loading-indicator">Loading...</div>'
12368    };
12369
12370 /**
12371  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12372  *Usage:
12373  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12374  * @param {String/HTMLElement/Roo.Element} el The element to update
12375  * @param {String} url The url
12376  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12377  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12378  * @static
12379  * @deprecated
12380  * @member Roo.UpdateManager
12381  */
12382 Roo.UpdateManager.updateElement = function(el, url, params, options){
12383     var um = Roo.get(el, true).getUpdateManager();
12384     Roo.apply(um, options);
12385     um.update(url, params, options ? options.callback : null);
12386 };
12387 // alias for backwards compat
12388 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12389 /**
12390  * @class Roo.UpdateManager.BasicRenderer
12391  * Default Content renderer. Updates the elements innerHTML with the responseText.
12392  */
12393 Roo.UpdateManager.BasicRenderer = function(){};
12394
12395 Roo.UpdateManager.BasicRenderer.prototype = {
12396     /**
12397      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12398      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12399      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12400      * @param {Roo.Element} el The element being rendered
12401      * @param {Object} response The YUI Connect response object
12402      * @param {UpdateManager} updateManager The calling update manager
12403      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12404      */
12405      render : function(el, response, updateManager, callback){
12406         el.update(response.responseText, updateManager.loadScripts, callback);
12407     }
12408 };
12409 /*
12410  * Based on:
12411  * Roo JS
12412  * (c)) Alan Knowles
12413  * Licence : LGPL
12414  */
12415
12416
12417 /**
12418  * @class Roo.DomTemplate
12419  * @extends Roo.Template
12420  * An effort at a dom based template engine..
12421  *
12422  * Similar to XTemplate, except it uses dom parsing to create the template..
12423  *
12424  * Supported features:
12425  *
12426  *  Tags:
12427
12428 <pre><code>
12429       {a_variable} - output encoded.
12430       {a_variable.format:("Y-m-d")} - call a method on the variable
12431       {a_variable:raw} - unencoded output
12432       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12433       {a_variable:this.method_on_template(...)} - call a method on the template object.
12434  
12435 </code></pre>
12436  *  The tpl tag:
12437 <pre><code>
12438         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12439         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12440         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12441         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12442   
12443 </code></pre>
12444  *      
12445  */
12446 Roo.DomTemplate = function()
12447 {
12448      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12449      if (this.html) {
12450         this.compile();
12451      }
12452 };
12453
12454
12455 Roo.extend(Roo.DomTemplate, Roo.Template, {
12456     /**
12457      * id counter for sub templates.
12458      */
12459     id : 0,
12460     /**
12461      * flag to indicate if dom parser is inside a pre,
12462      * it will strip whitespace if not.
12463      */
12464     inPre : false,
12465     
12466     /**
12467      * The various sub templates
12468      */
12469     tpls : false,
12470     
12471     
12472     
12473     /**
12474      *
12475      * basic tag replacing syntax
12476      * WORD:WORD()
12477      *
12478      * // you can fake an object call by doing this
12479      *  x.t:(test,tesT) 
12480      * 
12481      */
12482     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12483     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12484     
12485     iterChild : function (node, method) {
12486         
12487         var oldPre = this.inPre;
12488         if (node.tagName == 'PRE') {
12489             this.inPre = true;
12490         }
12491         for( var i = 0; i < node.childNodes.length; i++) {
12492             method.call(this, node.childNodes[i]);
12493         }
12494         this.inPre = oldPre;
12495     },
12496     
12497     
12498     
12499     /**
12500      * compile the template
12501      *
12502      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12503      *
12504      */
12505     compile: function()
12506     {
12507         var s = this.html;
12508         
12509         // covert the html into DOM...
12510         var doc = false;
12511         var div =false;
12512         try {
12513             doc = document.implementation.createHTMLDocument("");
12514             doc.documentElement.innerHTML =   this.html  ;
12515             div = doc.documentElement;
12516         } catch (e) {
12517             // old IE... - nasty -- it causes all sorts of issues.. with
12518             // images getting pulled from server..
12519             div = document.createElement('div');
12520             div.innerHTML = this.html;
12521         }
12522         //doc.documentElement.innerHTML = htmlBody
12523          
12524         
12525         
12526         this.tpls = [];
12527         var _t = this;
12528         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12529         
12530         var tpls = this.tpls;
12531         
12532         // create a top level template from the snippet..
12533         
12534         //Roo.log(div.innerHTML);
12535         
12536         var tpl = {
12537             uid : 'master',
12538             id : this.id++,
12539             attr : false,
12540             value : false,
12541             body : div.innerHTML,
12542             
12543             forCall : false,
12544             execCall : false,
12545             dom : div,
12546             isTop : true
12547             
12548         };
12549         tpls.unshift(tpl);
12550         
12551         
12552         // compile them...
12553         this.tpls = [];
12554         Roo.each(tpls, function(tp){
12555             this.compileTpl(tp);
12556             this.tpls[tp.id] = tp;
12557         }, this);
12558         
12559         this.master = tpls[0];
12560         return this;
12561         
12562         
12563     },
12564     
12565     compileNode : function(node, istop) {
12566         // test for
12567         //Roo.log(node);
12568         
12569         
12570         // skip anything not a tag..
12571         if (node.nodeType != 1) {
12572             if (node.nodeType == 3 && !this.inPre) {
12573                 // reduce white space..
12574                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12575                 
12576             }
12577             return;
12578         }
12579         
12580         var tpl = {
12581             uid : false,
12582             id : false,
12583             attr : false,
12584             value : false,
12585             body : '',
12586             
12587             forCall : false,
12588             execCall : false,
12589             dom : false,
12590             isTop : istop
12591             
12592             
12593         };
12594         
12595         
12596         switch(true) {
12597             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12598             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12599             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12600             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12601             // no default..
12602         }
12603         
12604         
12605         if (!tpl.attr) {
12606             // just itterate children..
12607             this.iterChild(node,this.compileNode);
12608             return;
12609         }
12610         tpl.uid = this.id++;
12611         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12612         node.removeAttribute('roo-'+ tpl.attr);
12613         if (tpl.attr != 'name') {
12614             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12615             node.parentNode.replaceChild(placeholder,  node);
12616         } else {
12617             
12618             var placeholder =  document.createElement('span');
12619             placeholder.className = 'roo-tpl-' + tpl.value;
12620             node.parentNode.replaceChild(placeholder,  node);
12621         }
12622         
12623         // parent now sees '{domtplXXXX}
12624         this.iterChild(node,this.compileNode);
12625         
12626         // we should now have node body...
12627         var div = document.createElement('div');
12628         div.appendChild(node);
12629         tpl.dom = node;
12630         // this has the unfortunate side effect of converting tagged attributes
12631         // eg. href="{...}" into %7C...%7D
12632         // this has been fixed by searching for those combo's although it's a bit hacky..
12633         
12634         
12635         tpl.body = div.innerHTML;
12636         
12637         
12638          
12639         tpl.id = tpl.uid;
12640         switch(tpl.attr) {
12641             case 'for' :
12642                 switch (tpl.value) {
12643                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12644                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12645                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12646                 }
12647                 break;
12648             
12649             case 'exec':
12650                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12651                 break;
12652             
12653             case 'if':     
12654                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12655                 break;
12656             
12657             case 'name':
12658                 tpl.id  = tpl.value; // replace non characters???
12659                 break;
12660             
12661         }
12662         
12663         
12664         this.tpls.push(tpl);
12665         
12666         
12667         
12668     },
12669     
12670     
12671     
12672     
12673     /**
12674      * Compile a segment of the template into a 'sub-template'
12675      *
12676      * 
12677      * 
12678      *
12679      */
12680     compileTpl : function(tpl)
12681     {
12682         var fm = Roo.util.Format;
12683         var useF = this.disableFormats !== true;
12684         
12685         var sep = Roo.isGecko ? "+\n" : ",\n";
12686         
12687         var undef = function(str) {
12688             Roo.debug && Roo.log("Property not found :"  + str);
12689             return '';
12690         };
12691           
12692         //Roo.log(tpl.body);
12693         
12694         
12695         
12696         var fn = function(m, lbrace, name, format, args)
12697         {
12698             //Roo.log("ARGS");
12699             //Roo.log(arguments);
12700             args = args ? args.replace(/\\'/g,"'") : args;
12701             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12702             if (typeof(format) == 'undefined') {
12703                 format =  'htmlEncode'; 
12704             }
12705             if (format == 'raw' ) {
12706                 format = false;
12707             }
12708             
12709             if(name.substr(0, 6) == 'domtpl'){
12710                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12711             }
12712             
12713             // build an array of options to determine if value is undefined..
12714             
12715             // basically get 'xxxx.yyyy' then do
12716             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12717             //    (function () { Roo.log("Property not found"); return ''; })() :
12718             //    ......
12719             
12720             var udef_ar = [];
12721             var lookfor = '';
12722             Roo.each(name.split('.'), function(st) {
12723                 lookfor += (lookfor.length ? '.': '') + st;
12724                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12725             });
12726             
12727             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12728             
12729             
12730             if(format && useF){
12731                 
12732                 args = args ? ',' + args : "";
12733                  
12734                 if(format.substr(0, 5) != "this."){
12735                     format = "fm." + format + '(';
12736                 }else{
12737                     format = 'this.call("'+ format.substr(5) + '", ';
12738                     args = ", values";
12739                 }
12740                 
12741                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12742             }
12743              
12744             if (args && args.length) {
12745                 // called with xxyx.yuu:(test,test)
12746                 // change to ()
12747                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12748             }
12749             // raw.. - :raw modifier..
12750             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12751             
12752         };
12753         var body;
12754         // branched to use + in gecko and [].join() in others
12755         if(Roo.isGecko){
12756             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12757                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12758                     "';};};";
12759         }else{
12760             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12761             body.push(tpl.body.replace(/(\r\n|\n)/g,
12762                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12763             body.push("'].join('');};};");
12764             body = body.join('');
12765         }
12766         
12767         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12768        
12769         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12770         eval(body);
12771         
12772         return this;
12773     },
12774      
12775     /**
12776      * same as applyTemplate, except it's done to one of the subTemplates
12777      * when using named templates, you can do:
12778      *
12779      * var str = pl.applySubTemplate('your-name', values);
12780      *
12781      * 
12782      * @param {Number} id of the template
12783      * @param {Object} values to apply to template
12784      * @param {Object} parent (normaly the instance of this object)
12785      */
12786     applySubTemplate : function(id, values, parent)
12787     {
12788         
12789         
12790         var t = this.tpls[id];
12791         
12792         
12793         try { 
12794             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12795                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12796                 return '';
12797             }
12798         } catch(e) {
12799             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12800             Roo.log(values);
12801           
12802             return '';
12803         }
12804         try { 
12805             
12806             if(t.execCall && t.execCall.call(this, values, parent)){
12807                 return '';
12808             }
12809         } catch(e) {
12810             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12811             Roo.log(values);
12812             return '';
12813         }
12814         
12815         try {
12816             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12817             parent = t.target ? values : parent;
12818             if(t.forCall && vs instanceof Array){
12819                 var buf = [];
12820                 for(var i = 0, len = vs.length; i < len; i++){
12821                     try {
12822                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12823                     } catch (e) {
12824                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12825                         Roo.log(e.body);
12826                         //Roo.log(t.compiled);
12827                         Roo.log(vs[i]);
12828                     }   
12829                 }
12830                 return buf.join('');
12831             }
12832         } catch (e) {
12833             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12834             Roo.log(values);
12835             return '';
12836         }
12837         try {
12838             return t.compiled.call(this, vs, parent);
12839         } catch (e) {
12840             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12841             Roo.log(e.body);
12842             //Roo.log(t.compiled);
12843             Roo.log(values);
12844             return '';
12845         }
12846     },
12847
12848    
12849
12850     applyTemplate : function(values){
12851         return this.master.compiled.call(this, values, {});
12852         //var s = this.subs;
12853     },
12854
12855     apply : function(){
12856         return this.applyTemplate.apply(this, arguments);
12857     }
12858
12859  });
12860
12861 Roo.DomTemplate.from = function(el){
12862     el = Roo.getDom(el);
12863     return new Roo.Domtemplate(el.value || el.innerHTML);
12864 };/*
12865  * Based on:
12866  * Ext JS Library 1.1.1
12867  * Copyright(c) 2006-2007, Ext JS, LLC.
12868  *
12869  * Originally Released Under LGPL - original licence link has changed is not relivant.
12870  *
12871  * Fork - LGPL
12872  * <script type="text/javascript">
12873  */
12874
12875 /**
12876  * @class Roo.util.DelayedTask
12877  * Provides a convenient method of performing setTimeout where a new
12878  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12879  * You can use this class to buffer
12880  * the keypress events for a certain number of milliseconds, and perform only if they stop
12881  * for that amount of time.
12882  * @constructor The parameters to this constructor serve as defaults and are not required.
12883  * @param {Function} fn (optional) The default function to timeout
12884  * @param {Object} scope (optional) The default scope of that timeout
12885  * @param {Array} args (optional) The default Array of arguments
12886  */
12887 Roo.util.DelayedTask = function(fn, scope, args){
12888     var id = null, d, t;
12889
12890     var call = function(){
12891         var now = new Date().getTime();
12892         if(now - t >= d){
12893             clearInterval(id);
12894             id = null;
12895             fn.apply(scope, args || []);
12896         }
12897     };
12898     /**
12899      * Cancels any pending timeout and queues a new one
12900      * @param {Number} delay The milliseconds to delay
12901      * @param {Function} newFn (optional) Overrides function passed to constructor
12902      * @param {Object} newScope (optional) Overrides scope passed to constructor
12903      * @param {Array} newArgs (optional) Overrides args passed to constructor
12904      */
12905     this.delay = function(delay, newFn, newScope, newArgs){
12906         if(id && delay != d){
12907             this.cancel();
12908         }
12909         d = delay;
12910         t = new Date().getTime();
12911         fn = newFn || fn;
12912         scope = newScope || scope;
12913         args = newArgs || args;
12914         if(!id){
12915             id = setInterval(call, d);
12916         }
12917     };
12918
12919     /**
12920      * Cancel the last queued timeout
12921      */
12922     this.cancel = function(){
12923         if(id){
12924             clearInterval(id);
12925             id = null;
12926         }
12927     };
12928 };/*
12929  * Based on:
12930  * Ext JS Library 1.1.1
12931  * Copyright(c) 2006-2007, Ext JS, LLC.
12932  *
12933  * Originally Released Under LGPL - original licence link has changed is not relivant.
12934  *
12935  * Fork - LGPL
12936  * <script type="text/javascript">
12937  */
12938  
12939  
12940 Roo.util.TaskRunner = function(interval){
12941     interval = interval || 10;
12942     var tasks = [], removeQueue = [];
12943     var id = 0;
12944     var running = false;
12945
12946     var stopThread = function(){
12947         running = false;
12948         clearInterval(id);
12949         id = 0;
12950     };
12951
12952     var startThread = function(){
12953         if(!running){
12954             running = true;
12955             id = setInterval(runTasks, interval);
12956         }
12957     };
12958
12959     var removeTask = function(task){
12960         removeQueue.push(task);
12961         if(task.onStop){
12962             task.onStop();
12963         }
12964     };
12965
12966     var runTasks = function(){
12967         if(removeQueue.length > 0){
12968             for(var i = 0, len = removeQueue.length; i < len; i++){
12969                 tasks.remove(removeQueue[i]);
12970             }
12971             removeQueue = [];
12972             if(tasks.length < 1){
12973                 stopThread();
12974                 return;
12975             }
12976         }
12977         var now = new Date().getTime();
12978         for(var i = 0, len = tasks.length; i < len; ++i){
12979             var t = tasks[i];
12980             var itime = now - t.taskRunTime;
12981             if(t.interval <= itime){
12982                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12983                 t.taskRunTime = now;
12984                 if(rt === false || t.taskRunCount === t.repeat){
12985                     removeTask(t);
12986                     return;
12987                 }
12988             }
12989             if(t.duration && t.duration <= (now - t.taskStartTime)){
12990                 removeTask(t);
12991             }
12992         }
12993     };
12994
12995     /**
12996      * Queues a new task.
12997      * @param {Object} task
12998      */
12999     this.start = function(task){
13000         tasks.push(task);
13001         task.taskStartTime = new Date().getTime();
13002         task.taskRunTime = 0;
13003         task.taskRunCount = 0;
13004         startThread();
13005         return task;
13006     };
13007
13008     this.stop = function(task){
13009         removeTask(task);
13010         return task;
13011     };
13012
13013     this.stopAll = function(){
13014         stopThread();
13015         for(var i = 0, len = tasks.length; i < len; i++){
13016             if(tasks[i].onStop){
13017                 tasks[i].onStop();
13018             }
13019         }
13020         tasks = [];
13021         removeQueue = [];
13022     };
13023 };
13024
13025 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13026  * Based on:
13027  * Ext JS Library 1.1.1
13028  * Copyright(c) 2006-2007, Ext JS, LLC.
13029  *
13030  * Originally Released Under LGPL - original licence link has changed is not relivant.
13031  *
13032  * Fork - LGPL
13033  * <script type="text/javascript">
13034  */
13035
13036  
13037 /**
13038  * @class Roo.util.MixedCollection
13039  * @extends Roo.util.Observable
13040  * A Collection class that maintains both numeric indexes and keys and exposes events.
13041  * @constructor
13042  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13043  * collection (defaults to false)
13044  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13045  * and return the key value for that item.  This is used when available to look up the key on items that
13046  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13047  * equivalent to providing an implementation for the {@link #getKey} method.
13048  */
13049 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13050     this.items = [];
13051     this.map = {};
13052     this.keys = [];
13053     this.length = 0;
13054     this.addEvents({
13055         /**
13056          * @event clear
13057          * Fires when the collection is cleared.
13058          */
13059         "clear" : true,
13060         /**
13061          * @event add
13062          * Fires when an item is added to the collection.
13063          * @param {Number} index The index at which the item was added.
13064          * @param {Object} o The item added.
13065          * @param {String} key The key associated with the added item.
13066          */
13067         "add" : true,
13068         /**
13069          * @event replace
13070          * Fires when an item is replaced in the collection.
13071          * @param {String} key he key associated with the new added.
13072          * @param {Object} old The item being replaced.
13073          * @param {Object} new The new item.
13074          */
13075         "replace" : true,
13076         /**
13077          * @event remove
13078          * Fires when an item is removed from the collection.
13079          * @param {Object} o The item being removed.
13080          * @param {String} key (optional) The key associated with the removed item.
13081          */
13082         "remove" : true,
13083         "sort" : true
13084     });
13085     this.allowFunctions = allowFunctions === true;
13086     if(keyFn){
13087         this.getKey = keyFn;
13088     }
13089     Roo.util.MixedCollection.superclass.constructor.call(this);
13090 };
13091
13092 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13093     allowFunctions : false,
13094     
13095 /**
13096  * Adds an item to the collection.
13097  * @param {String} key The key to associate with the item
13098  * @param {Object} o The item to add.
13099  * @return {Object} The item added.
13100  */
13101     add : function(key, o){
13102         if(arguments.length == 1){
13103             o = arguments[0];
13104             key = this.getKey(o);
13105         }
13106         if(typeof key == "undefined" || key === null){
13107             this.length++;
13108             this.items.push(o);
13109             this.keys.push(null);
13110         }else{
13111             var old = this.map[key];
13112             if(old){
13113                 return this.replace(key, o);
13114             }
13115             this.length++;
13116             this.items.push(o);
13117             this.map[key] = o;
13118             this.keys.push(key);
13119         }
13120         this.fireEvent("add", this.length-1, o, key);
13121         return o;
13122     },
13123        
13124 /**
13125   * MixedCollection has a generic way to fetch keys if you implement getKey.
13126 <pre><code>
13127 // normal way
13128 var mc = new Roo.util.MixedCollection();
13129 mc.add(someEl.dom.id, someEl);
13130 mc.add(otherEl.dom.id, otherEl);
13131 //and so on
13132
13133 // using getKey
13134 var mc = new Roo.util.MixedCollection();
13135 mc.getKey = function(el){
13136    return el.dom.id;
13137 };
13138 mc.add(someEl);
13139 mc.add(otherEl);
13140
13141 // or via the constructor
13142 var mc = new Roo.util.MixedCollection(false, function(el){
13143    return el.dom.id;
13144 });
13145 mc.add(someEl);
13146 mc.add(otherEl);
13147 </code></pre>
13148  * @param o {Object} The item for which to find the key.
13149  * @return {Object} The key for the passed item.
13150  */
13151     getKey : function(o){
13152          return o.id; 
13153     },
13154    
13155 /**
13156  * Replaces an item in the collection.
13157  * @param {String} key The key associated with the item to replace, or the item to replace.
13158  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13159  * @return {Object}  The new item.
13160  */
13161     replace : function(key, o){
13162         if(arguments.length == 1){
13163             o = arguments[0];
13164             key = this.getKey(o);
13165         }
13166         var old = this.item(key);
13167         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13168              return this.add(key, o);
13169         }
13170         var index = this.indexOfKey(key);
13171         this.items[index] = o;
13172         this.map[key] = o;
13173         this.fireEvent("replace", key, old, o);
13174         return o;
13175     },
13176    
13177 /**
13178  * Adds all elements of an Array or an Object to the collection.
13179  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13180  * an Array of values, each of which are added to the collection.
13181  */
13182     addAll : function(objs){
13183         if(arguments.length > 1 || objs instanceof Array){
13184             var args = arguments.length > 1 ? arguments : objs;
13185             for(var i = 0, len = args.length; i < len; i++){
13186                 this.add(args[i]);
13187             }
13188         }else{
13189             for(var key in objs){
13190                 if(this.allowFunctions || typeof objs[key] != "function"){
13191                     this.add(key, objs[key]);
13192                 }
13193             }
13194         }
13195     },
13196    
13197 /**
13198  * Executes the specified function once for every item in the collection, passing each
13199  * item as the first and only parameter. returning false from the function will stop the iteration.
13200  * @param {Function} fn The function to execute for each item.
13201  * @param {Object} scope (optional) The scope in which to execute the function.
13202  */
13203     each : function(fn, scope){
13204         var items = [].concat(this.items); // each safe for removal
13205         for(var i = 0, len = items.length; i < len; i++){
13206             if(fn.call(scope || items[i], items[i], i, len) === false){
13207                 break;
13208             }
13209         }
13210     },
13211    
13212 /**
13213  * Executes the specified function once for every key in the collection, passing each
13214  * key, and its associated item as the first two parameters.
13215  * @param {Function} fn The function to execute for each item.
13216  * @param {Object} scope (optional) The scope in which to execute the function.
13217  */
13218     eachKey : function(fn, scope){
13219         for(var i = 0, len = this.keys.length; i < len; i++){
13220             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13221         }
13222     },
13223    
13224 /**
13225  * Returns the first item in the collection which elicits a true return value from the
13226  * passed selection function.
13227  * @param {Function} fn The selection function to execute for each item.
13228  * @param {Object} scope (optional) The scope in which to execute the function.
13229  * @return {Object} The first item in the collection which returned true from the selection function.
13230  */
13231     find : function(fn, scope){
13232         for(var i = 0, len = this.items.length; i < len; i++){
13233             if(fn.call(scope || window, this.items[i], this.keys[i])){
13234                 return this.items[i];
13235             }
13236         }
13237         return null;
13238     },
13239    
13240 /**
13241  * Inserts an item at the specified index in the collection.
13242  * @param {Number} index The index to insert the item at.
13243  * @param {String} key The key to associate with the new item, or the item itself.
13244  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13245  * @return {Object} The item inserted.
13246  */
13247     insert : function(index, key, o){
13248         if(arguments.length == 2){
13249             o = arguments[1];
13250             key = this.getKey(o);
13251         }
13252         if(index >= this.length){
13253             return this.add(key, o);
13254         }
13255         this.length++;
13256         this.items.splice(index, 0, o);
13257         if(typeof key != "undefined" && key != null){
13258             this.map[key] = o;
13259         }
13260         this.keys.splice(index, 0, key);
13261         this.fireEvent("add", index, o, key);
13262         return o;
13263     },
13264    
13265 /**
13266  * Removed an item from the collection.
13267  * @param {Object} o The item to remove.
13268  * @return {Object} The item removed.
13269  */
13270     remove : function(o){
13271         return this.removeAt(this.indexOf(o));
13272     },
13273    
13274 /**
13275  * Remove an item from a specified index in the collection.
13276  * @param {Number} index The index within the collection of the item to remove.
13277  */
13278     removeAt : function(index){
13279         if(index < this.length && index >= 0){
13280             this.length--;
13281             var o = this.items[index];
13282             this.items.splice(index, 1);
13283             var key = this.keys[index];
13284             if(typeof key != "undefined"){
13285                 delete this.map[key];
13286             }
13287             this.keys.splice(index, 1);
13288             this.fireEvent("remove", o, key);
13289         }
13290     },
13291    
13292 /**
13293  * Removed an item associated with the passed key fom the collection.
13294  * @param {String} key The key of the item to remove.
13295  */
13296     removeKey : function(key){
13297         return this.removeAt(this.indexOfKey(key));
13298     },
13299    
13300 /**
13301  * Returns the number of items in the collection.
13302  * @return {Number} the number of items in the collection.
13303  */
13304     getCount : function(){
13305         return this.length; 
13306     },
13307    
13308 /**
13309  * Returns index within the collection of the passed Object.
13310  * @param {Object} o The item to find the index of.
13311  * @return {Number} index of the item.
13312  */
13313     indexOf : function(o){
13314         if(!this.items.indexOf){
13315             for(var i = 0, len = this.items.length; i < len; i++){
13316                 if(this.items[i] == o) {
13317                     return i;
13318                 }
13319             }
13320             return -1;
13321         }else{
13322             return this.items.indexOf(o);
13323         }
13324     },
13325    
13326 /**
13327  * Returns index within the collection of the passed key.
13328  * @param {String} key The key to find the index of.
13329  * @return {Number} index of the key.
13330  */
13331     indexOfKey : function(key){
13332         if(!this.keys.indexOf){
13333             for(var i = 0, len = this.keys.length; i < len; i++){
13334                 if(this.keys[i] == key) {
13335                     return i;
13336                 }
13337             }
13338             return -1;
13339         }else{
13340             return this.keys.indexOf(key);
13341         }
13342     },
13343    
13344 /**
13345  * Returns the item associated with the passed key OR index. Key has priority over index.
13346  * @param {String/Number} key The key or index of the item.
13347  * @return {Object} The item associated with the passed key.
13348  */
13349     item : function(key){
13350         if (key === 'length') {
13351             return null;
13352         }
13353         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13354         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13355     },
13356     
13357 /**
13358  * Returns the item at the specified index.
13359  * @param {Number} index The index of the item.
13360  * @return {Object}
13361  */
13362     itemAt : function(index){
13363         return this.items[index];
13364     },
13365     
13366 /**
13367  * Returns the item associated with the passed key.
13368  * @param {String/Number} key The key of the item.
13369  * @return {Object} The item associated with the passed key.
13370  */
13371     key : function(key){
13372         return this.map[key];
13373     },
13374    
13375 /**
13376  * Returns true if the collection contains the passed Object as an item.
13377  * @param {Object} o  The Object to look for in the collection.
13378  * @return {Boolean} True if the collection contains the Object as an item.
13379  */
13380     contains : function(o){
13381         return this.indexOf(o) != -1;
13382     },
13383    
13384 /**
13385  * Returns true if the collection contains the passed Object as a key.
13386  * @param {String} key The key to look for in the collection.
13387  * @return {Boolean} True if the collection contains the Object as a key.
13388  */
13389     containsKey : function(key){
13390         return typeof this.map[key] != "undefined";
13391     },
13392    
13393 /**
13394  * Removes all items from the collection.
13395  */
13396     clear : function(){
13397         this.length = 0;
13398         this.items = [];
13399         this.keys = [];
13400         this.map = {};
13401         this.fireEvent("clear");
13402     },
13403    
13404 /**
13405  * Returns the first item in the collection.
13406  * @return {Object} the first item in the collection..
13407  */
13408     first : function(){
13409         return this.items[0]; 
13410     },
13411    
13412 /**
13413  * Returns the last item in the collection.
13414  * @return {Object} the last item in the collection..
13415  */
13416     last : function(){
13417         return this.items[this.length-1];   
13418     },
13419     
13420     _sort : function(property, dir, fn){
13421         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13422         fn = fn || function(a, b){
13423             return a-b;
13424         };
13425         var c = [], k = this.keys, items = this.items;
13426         for(var i = 0, len = items.length; i < len; i++){
13427             c[c.length] = {key: k[i], value: items[i], index: i};
13428         }
13429         c.sort(function(a, b){
13430             var v = fn(a[property], b[property]) * dsc;
13431             if(v == 0){
13432                 v = (a.index < b.index ? -1 : 1);
13433             }
13434             return v;
13435         });
13436         for(var i = 0, len = c.length; i < len; i++){
13437             items[i] = c[i].value;
13438             k[i] = c[i].key;
13439         }
13440         this.fireEvent("sort", this);
13441     },
13442     
13443     /**
13444      * Sorts this collection with the passed comparison function
13445      * @param {String} direction (optional) "ASC" or "DESC"
13446      * @param {Function} fn (optional) comparison function
13447      */
13448     sort : function(dir, fn){
13449         this._sort("value", dir, fn);
13450     },
13451     
13452     /**
13453      * Sorts this collection by keys
13454      * @param {String} direction (optional) "ASC" or "DESC"
13455      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13456      */
13457     keySort : function(dir, fn){
13458         this._sort("key", dir, fn || function(a, b){
13459             return String(a).toUpperCase()-String(b).toUpperCase();
13460         });
13461     },
13462     
13463     /**
13464      * Returns a range of items in this collection
13465      * @param {Number} startIndex (optional) defaults to 0
13466      * @param {Number} endIndex (optional) default to the last item
13467      * @return {Array} An array of items
13468      */
13469     getRange : function(start, end){
13470         var items = this.items;
13471         if(items.length < 1){
13472             return [];
13473         }
13474         start = start || 0;
13475         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13476         var r = [];
13477         if(start <= end){
13478             for(var i = start; i <= end; i++) {
13479                     r[r.length] = items[i];
13480             }
13481         }else{
13482             for(var i = start; i >= end; i--) {
13483                     r[r.length] = items[i];
13484             }
13485         }
13486         return r;
13487     },
13488         
13489     /**
13490      * Filter the <i>objects</i> in this collection by a specific property. 
13491      * Returns a new collection that has been filtered.
13492      * @param {String} property A property on your objects
13493      * @param {String/RegExp} value Either string that the property values 
13494      * should start with or a RegExp to test against the property
13495      * @return {MixedCollection} The new filtered collection
13496      */
13497     filter : function(property, value){
13498         if(!value.exec){ // not a regex
13499             value = String(value);
13500             if(value.length == 0){
13501                 return this.clone();
13502             }
13503             value = new RegExp("^" + Roo.escapeRe(value), "i");
13504         }
13505         return this.filterBy(function(o){
13506             return o && value.test(o[property]);
13507         });
13508         },
13509     
13510     /**
13511      * Filter by a function. * Returns a new collection that has been filtered.
13512      * The passed function will be called with each 
13513      * object in the collection. If the function returns true, the value is included 
13514      * otherwise it is filtered.
13515      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13516      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13517      * @return {MixedCollection} The new filtered collection
13518      */
13519     filterBy : function(fn, scope){
13520         var r = new Roo.util.MixedCollection();
13521         r.getKey = this.getKey;
13522         var k = this.keys, it = this.items;
13523         for(var i = 0, len = it.length; i < len; i++){
13524             if(fn.call(scope||this, it[i], k[i])){
13525                                 r.add(k[i], it[i]);
13526                         }
13527         }
13528         return r;
13529     },
13530     
13531     /**
13532      * Creates a duplicate of this collection
13533      * @return {MixedCollection}
13534      */
13535     clone : function(){
13536         var r = new Roo.util.MixedCollection();
13537         var k = this.keys, it = this.items;
13538         for(var i = 0, len = it.length; i < len; i++){
13539             r.add(k[i], it[i]);
13540         }
13541         r.getKey = this.getKey;
13542         return r;
13543     }
13544 });
13545 /**
13546  * Returns the item associated with the passed key or index.
13547  * @method
13548  * @param {String/Number} key The key or index of the item.
13549  * @return {Object} The item associated with the passed key.
13550  */
13551 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13552  * Based on:
13553  * Ext JS Library 1.1.1
13554  * Copyright(c) 2006-2007, Ext JS, LLC.
13555  *
13556  * Originally Released Under LGPL - original licence link has changed is not relivant.
13557  *
13558  * Fork - LGPL
13559  * <script type="text/javascript">
13560  */
13561 /**
13562  * @class Roo.util.JSON
13563  * Modified version of Douglas Crockford"s json.js that doesn"t
13564  * mess with the Object prototype 
13565  * http://www.json.org/js.html
13566  * @singleton
13567  */
13568 Roo.util.JSON = new (function(){
13569     var useHasOwn = {}.hasOwnProperty ? true : false;
13570     
13571     // crashes Safari in some instances
13572     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13573     
13574     var pad = function(n) {
13575         return n < 10 ? "0" + n : n;
13576     };
13577     
13578     var m = {
13579         "\b": '\\b',
13580         "\t": '\\t',
13581         "\n": '\\n',
13582         "\f": '\\f',
13583         "\r": '\\r',
13584         '"' : '\\"',
13585         "\\": '\\\\'
13586     };
13587
13588     var encodeString = function(s){
13589         if (/["\\\x00-\x1f]/.test(s)) {
13590             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13591                 var c = m[b];
13592                 if(c){
13593                     return c;
13594                 }
13595                 c = b.charCodeAt();
13596                 return "\\u00" +
13597                     Math.floor(c / 16).toString(16) +
13598                     (c % 16).toString(16);
13599             }) + '"';
13600         }
13601         return '"' + s + '"';
13602     };
13603     
13604     var encodeArray = function(o){
13605         var a = ["["], b, i, l = o.length, v;
13606             for (i = 0; i < l; i += 1) {
13607                 v = o[i];
13608                 switch (typeof v) {
13609                     case "undefined":
13610                     case "function":
13611                     case "unknown":
13612                         break;
13613                     default:
13614                         if (b) {
13615                             a.push(',');
13616                         }
13617                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13618                         b = true;
13619                 }
13620             }
13621             a.push("]");
13622             return a.join("");
13623     };
13624     
13625     var encodeDate = function(o){
13626         return '"' + o.getFullYear() + "-" +
13627                 pad(o.getMonth() + 1) + "-" +
13628                 pad(o.getDate()) + "T" +
13629                 pad(o.getHours()) + ":" +
13630                 pad(o.getMinutes()) + ":" +
13631                 pad(o.getSeconds()) + '"';
13632     };
13633     
13634     /**
13635      * Encodes an Object, Array or other value
13636      * @param {Mixed} o The variable to encode
13637      * @return {String} The JSON string
13638      */
13639     this.encode = function(o)
13640     {
13641         // should this be extended to fully wrap stringify..
13642         
13643         if(typeof o == "undefined" || o === null){
13644             return "null";
13645         }else if(o instanceof Array){
13646             return encodeArray(o);
13647         }else if(o instanceof Date){
13648             return encodeDate(o);
13649         }else if(typeof o == "string"){
13650             return encodeString(o);
13651         }else if(typeof o == "number"){
13652             return isFinite(o) ? String(o) : "null";
13653         }else if(typeof o == "boolean"){
13654             return String(o);
13655         }else {
13656             var a = ["{"], b, i, v;
13657             for (i in o) {
13658                 if(!useHasOwn || o.hasOwnProperty(i)) {
13659                     v = o[i];
13660                     switch (typeof v) {
13661                     case "undefined":
13662                     case "function":
13663                     case "unknown":
13664                         break;
13665                     default:
13666                         if(b){
13667                             a.push(',');
13668                         }
13669                         a.push(this.encode(i), ":",
13670                                 v === null ? "null" : this.encode(v));
13671                         b = true;
13672                     }
13673                 }
13674             }
13675             a.push("}");
13676             return a.join("");
13677         }
13678     };
13679     
13680     /**
13681      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13682      * @param {String} json The JSON string
13683      * @return {Object} The resulting object
13684      */
13685     this.decode = function(json){
13686         
13687         return  /** eval:var:json */ eval("(" + json + ')');
13688     };
13689 })();
13690 /** 
13691  * Shorthand for {@link Roo.util.JSON#encode}
13692  * @member Roo encode 
13693  * @method */
13694 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13695 /** 
13696  * Shorthand for {@link Roo.util.JSON#decode}
13697  * @member Roo decode 
13698  * @method */
13699 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13700 /*
13701  * Based on:
13702  * Ext JS Library 1.1.1
13703  * Copyright(c) 2006-2007, Ext JS, LLC.
13704  *
13705  * Originally Released Under LGPL - original licence link has changed is not relivant.
13706  *
13707  * Fork - LGPL
13708  * <script type="text/javascript">
13709  */
13710  
13711 /**
13712  * @class Roo.util.Format
13713  * Reusable data formatting functions
13714  * @singleton
13715  */
13716 Roo.util.Format = function(){
13717     var trimRe = /^\s+|\s+$/g;
13718     return {
13719         /**
13720          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13721          * @param {String} value The string to truncate
13722          * @param {Number} length The maximum length to allow before truncating
13723          * @return {String} The converted text
13724          */
13725         ellipsis : function(value, len){
13726             if(value && value.length > len){
13727                 return value.substr(0, len-3)+"...";
13728             }
13729             return value;
13730         },
13731
13732         /**
13733          * Checks a reference and converts it to empty string if it is undefined
13734          * @param {Mixed} value Reference to check
13735          * @return {Mixed} Empty string if converted, otherwise the original value
13736          */
13737         undef : function(value){
13738             return typeof value != "undefined" ? value : "";
13739         },
13740
13741         /**
13742          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13743          * @param {String} value The string to encode
13744          * @return {String} The encoded text
13745          */
13746         htmlEncode : function(value){
13747             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13748         },
13749
13750         /**
13751          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13752          * @param {String} value The string to decode
13753          * @return {String} The decoded text
13754          */
13755         htmlDecode : function(value){
13756             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13757         },
13758
13759         /**
13760          * Trims any whitespace from either side of a string
13761          * @param {String} value The text to trim
13762          * @return {String} The trimmed text
13763          */
13764         trim : function(value){
13765             return String(value).replace(trimRe, "");
13766         },
13767
13768         /**
13769          * Returns a substring from within an original string
13770          * @param {String} value The original text
13771          * @param {Number} start The start index of the substring
13772          * @param {Number} length The length of the substring
13773          * @return {String} The substring
13774          */
13775         substr : function(value, start, length){
13776             return String(value).substr(start, length);
13777         },
13778
13779         /**
13780          * Converts a string to all lower case letters
13781          * @param {String} value The text to convert
13782          * @return {String} The converted text
13783          */
13784         lowercase : function(value){
13785             return String(value).toLowerCase();
13786         },
13787
13788         /**
13789          * Converts a string to all upper case letters
13790          * @param {String} value The text to convert
13791          * @return {String} The converted text
13792          */
13793         uppercase : function(value){
13794             return String(value).toUpperCase();
13795         },
13796
13797         /**
13798          * Converts the first character only of a string to upper case
13799          * @param {String} value The text to convert
13800          * @return {String} The converted text
13801          */
13802         capitalize : function(value){
13803             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13804         },
13805
13806         // private
13807         call : function(value, fn){
13808             if(arguments.length > 2){
13809                 var args = Array.prototype.slice.call(arguments, 2);
13810                 args.unshift(value);
13811                  
13812                 return /** eval:var:value */  eval(fn).apply(window, args);
13813             }else{
13814                 /** eval:var:value */
13815                 return /** eval:var:value */ eval(fn).call(window, value);
13816             }
13817         },
13818
13819        
13820         /**
13821          * safer version of Math.toFixed..??/
13822          * @param {Number/String} value The numeric value to format
13823          * @param {Number/String} value Decimal places 
13824          * @return {String} The formatted currency string
13825          */
13826         toFixed : function(v, n)
13827         {
13828             // why not use to fixed - precision is buggered???
13829             if (!n) {
13830                 return Math.round(v-0);
13831             }
13832             var fact = Math.pow(10,n+1);
13833             v = (Math.round((v-0)*fact))/fact;
13834             var z = (''+fact).substring(2);
13835             if (v == Math.floor(v)) {
13836                 return Math.floor(v) + '.' + z;
13837             }
13838             
13839             // now just padd decimals..
13840             var ps = String(v).split('.');
13841             var fd = (ps[1] + z);
13842             var r = fd.substring(0,n); 
13843             var rm = fd.substring(n); 
13844             if (rm < 5) {
13845                 return ps[0] + '.' + r;
13846             }
13847             r*=1; // turn it into a number;
13848             r++;
13849             if (String(r).length != n) {
13850                 ps[0]*=1;
13851                 ps[0]++;
13852                 r = String(r).substring(1); // chop the end off.
13853             }
13854             
13855             return ps[0] + '.' + r;
13856              
13857         },
13858         
13859         /**
13860          * Format a number as US currency
13861          * @param {Number/String} value The numeric value to format
13862          * @return {String} The formatted currency string
13863          */
13864         usMoney : function(v){
13865             return '$' + Roo.util.Format.number(v);
13866         },
13867         
13868         /**
13869          * Format a number
13870          * eventually this should probably emulate php's number_format
13871          * @param {Number/String} value The numeric value to format
13872          * @param {Number} decimals number of decimal places
13873          * @param {String} delimiter for thousands (default comma)
13874          * @return {String} The formatted currency string
13875          */
13876         number : function(v, decimals, thousandsDelimiter)
13877         {
13878             // multiply and round.
13879             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13880             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13881             
13882             var mul = Math.pow(10, decimals);
13883             var zero = String(mul).substring(1);
13884             v = (Math.round((v-0)*mul))/mul;
13885             
13886             // if it's '0' number.. then
13887             
13888             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13889             v = String(v);
13890             var ps = v.split('.');
13891             var whole = ps[0];
13892             
13893             var r = /(\d+)(\d{3})/;
13894             // add comma's
13895             
13896             if(thousandsDelimiter.length != 0) {
13897                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13898             } 
13899             
13900             var sub = ps[1] ?
13901                     // has decimals..
13902                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13903                     // does not have decimals
13904                     (decimals ? ('.' + zero) : '');
13905             
13906             
13907             return whole + sub ;
13908         },
13909         
13910         /**
13911          * Parse a value into a formatted date using the specified format pattern.
13912          * @param {Mixed} value The value to format
13913          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13914          * @return {String} The formatted date string
13915          */
13916         date : function(v, format){
13917             if(!v){
13918                 return "";
13919             }
13920             if(!(v instanceof Date)){
13921                 v = new Date(Date.parse(v));
13922             }
13923             return v.dateFormat(format || Roo.util.Format.defaults.date);
13924         },
13925
13926         /**
13927          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13928          * @param {String} format Any valid date format string
13929          * @return {Function} The date formatting function
13930          */
13931         dateRenderer : function(format){
13932             return function(v){
13933                 return Roo.util.Format.date(v, format);  
13934             };
13935         },
13936
13937         // private
13938         stripTagsRE : /<\/?[^>]+>/gi,
13939         
13940         /**
13941          * Strips all HTML tags
13942          * @param {Mixed} value The text from which to strip tags
13943          * @return {String} The stripped text
13944          */
13945         stripTags : function(v){
13946             return !v ? v : String(v).replace(this.stripTagsRE, "");
13947         }
13948     };
13949 }();
13950 Roo.util.Format.defaults = {
13951     date : 'd/M/Y'
13952 };/*
13953  * Based on:
13954  * Ext JS Library 1.1.1
13955  * Copyright(c) 2006-2007, Ext JS, LLC.
13956  *
13957  * Originally Released Under LGPL - original licence link has changed is not relivant.
13958  *
13959  * Fork - LGPL
13960  * <script type="text/javascript">
13961  */
13962
13963
13964  
13965
13966 /**
13967  * @class Roo.MasterTemplate
13968  * @extends Roo.Template
13969  * Provides a template that can have child templates. The syntax is:
13970 <pre><code>
13971 var t = new Roo.MasterTemplate(
13972         '&lt;select name="{name}"&gt;',
13973                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13974         '&lt;/select&gt;'
13975 );
13976 t.add('options', {value: 'foo', text: 'bar'});
13977 // or you can add multiple child elements in one shot
13978 t.addAll('options', [
13979     {value: 'foo', text: 'bar'},
13980     {value: 'foo2', text: 'bar2'},
13981     {value: 'foo3', text: 'bar3'}
13982 ]);
13983 // then append, applying the master template values
13984 t.append('my-form', {name: 'my-select'});
13985 </code></pre>
13986 * A name attribute for the child template is not required if you have only one child
13987 * template or you want to refer to them by index.
13988  */
13989 Roo.MasterTemplate = function(){
13990     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13991     this.originalHtml = this.html;
13992     var st = {};
13993     var m, re = this.subTemplateRe;
13994     re.lastIndex = 0;
13995     var subIndex = 0;
13996     while(m = re.exec(this.html)){
13997         var name = m[1], content = m[2];
13998         st[subIndex] = {
13999             name: name,
14000             index: subIndex,
14001             buffer: [],
14002             tpl : new Roo.Template(content)
14003         };
14004         if(name){
14005             st[name] = st[subIndex];
14006         }
14007         st[subIndex].tpl.compile();
14008         st[subIndex].tpl.call = this.call.createDelegate(this);
14009         subIndex++;
14010     }
14011     this.subCount = subIndex;
14012     this.subs = st;
14013 };
14014 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14015     /**
14016     * The regular expression used to match sub templates
14017     * @type RegExp
14018     * @property
14019     */
14020     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14021
14022     /**
14023      * Applies the passed values to a child template.
14024      * @param {String/Number} name (optional) The name or index of the child template
14025      * @param {Array/Object} values The values to be applied to the template
14026      * @return {MasterTemplate} this
14027      */
14028      add : function(name, values){
14029         if(arguments.length == 1){
14030             values = arguments[0];
14031             name = 0;
14032         }
14033         var s = this.subs[name];
14034         s.buffer[s.buffer.length] = s.tpl.apply(values);
14035         return this;
14036     },
14037
14038     /**
14039      * Applies all the passed values to a child template.
14040      * @param {String/Number} name (optional) The name or index of the child template
14041      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14042      * @param {Boolean} reset (optional) True to reset the template first
14043      * @return {MasterTemplate} this
14044      */
14045     fill : function(name, values, reset){
14046         var a = arguments;
14047         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14048             values = a[0];
14049             name = 0;
14050             reset = a[1];
14051         }
14052         if(reset){
14053             this.reset();
14054         }
14055         for(var i = 0, len = values.length; i < len; i++){
14056             this.add(name, values[i]);
14057         }
14058         return this;
14059     },
14060
14061     /**
14062      * Resets the template for reuse
14063      * @return {MasterTemplate} this
14064      */
14065      reset : function(){
14066         var s = this.subs;
14067         for(var i = 0; i < this.subCount; i++){
14068             s[i].buffer = [];
14069         }
14070         return this;
14071     },
14072
14073     applyTemplate : function(values){
14074         var s = this.subs;
14075         var replaceIndex = -1;
14076         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14077             return s[++replaceIndex].buffer.join("");
14078         });
14079         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14080     },
14081
14082     apply : function(){
14083         return this.applyTemplate.apply(this, arguments);
14084     },
14085
14086     compile : function(){return this;}
14087 });
14088
14089 /**
14090  * Alias for fill().
14091  * @method
14092  */
14093 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14094  /**
14095  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14096  * var tpl = Roo.MasterTemplate.from('element-id');
14097  * @param {String/HTMLElement} el
14098  * @param {Object} config
14099  * @static
14100  */
14101 Roo.MasterTemplate.from = function(el, config){
14102     el = Roo.getDom(el);
14103     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14104 };/*
14105  * Based on:
14106  * Ext JS Library 1.1.1
14107  * Copyright(c) 2006-2007, Ext JS, LLC.
14108  *
14109  * Originally Released Under LGPL - original licence link has changed is not relivant.
14110  *
14111  * Fork - LGPL
14112  * <script type="text/javascript">
14113  */
14114
14115  
14116 /**
14117  * @class Roo.util.CSS
14118  * Utility class for manipulating CSS rules
14119  * @singleton
14120  */
14121 Roo.util.CSS = function(){
14122         var rules = null;
14123         var doc = document;
14124
14125     var camelRe = /(-[a-z])/gi;
14126     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14127
14128    return {
14129    /**
14130     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14131     * tag and appended to the HEAD of the document.
14132     * @param {String|Object} cssText The text containing the css rules
14133     * @param {String} id An id to add to the stylesheet for later removal
14134     * @return {StyleSheet}
14135     */
14136     createStyleSheet : function(cssText, id){
14137         var ss;
14138         var head = doc.getElementsByTagName("head")[0];
14139         var nrules = doc.createElement("style");
14140         nrules.setAttribute("type", "text/css");
14141         if(id){
14142             nrules.setAttribute("id", id);
14143         }
14144         if (typeof(cssText) != 'string') {
14145             // support object maps..
14146             // not sure if this a good idea.. 
14147             // perhaps it should be merged with the general css handling
14148             // and handle js style props.
14149             var cssTextNew = [];
14150             for(var n in cssText) {
14151                 var citems = [];
14152                 for(var k in cssText[n]) {
14153                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14154                 }
14155                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14156                 
14157             }
14158             cssText = cssTextNew.join("\n");
14159             
14160         }
14161        
14162        
14163        if(Roo.isIE){
14164            head.appendChild(nrules);
14165            ss = nrules.styleSheet;
14166            ss.cssText = cssText;
14167        }else{
14168            try{
14169                 nrules.appendChild(doc.createTextNode(cssText));
14170            }catch(e){
14171                nrules.cssText = cssText; 
14172            }
14173            head.appendChild(nrules);
14174            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14175        }
14176        this.cacheStyleSheet(ss);
14177        return ss;
14178    },
14179
14180    /**
14181     * Removes a style or link tag by id
14182     * @param {String} id The id of the tag
14183     */
14184    removeStyleSheet : function(id){
14185        var existing = doc.getElementById(id);
14186        if(existing){
14187            existing.parentNode.removeChild(existing);
14188        }
14189    },
14190
14191    /**
14192     * Dynamically swaps an existing stylesheet reference for a new one
14193     * @param {String} id The id of an existing link tag to remove
14194     * @param {String} url The href of the new stylesheet to include
14195     */
14196    swapStyleSheet : function(id, url){
14197        this.removeStyleSheet(id);
14198        var ss = doc.createElement("link");
14199        ss.setAttribute("rel", "stylesheet");
14200        ss.setAttribute("type", "text/css");
14201        ss.setAttribute("id", id);
14202        ss.setAttribute("href", url);
14203        doc.getElementsByTagName("head")[0].appendChild(ss);
14204    },
14205    
14206    /**
14207     * Refresh the rule cache if you have dynamically added stylesheets
14208     * @return {Object} An object (hash) of rules indexed by selector
14209     */
14210    refreshCache : function(){
14211        return this.getRules(true);
14212    },
14213
14214    // private
14215    cacheStyleSheet : function(stylesheet){
14216        if(!rules){
14217            rules = {};
14218        }
14219        try{// try catch for cross domain access issue
14220            var ssRules = stylesheet.cssRules || stylesheet.rules;
14221            for(var j = ssRules.length-1; j >= 0; --j){
14222                rules[ssRules[j].selectorText] = ssRules[j];
14223            }
14224        }catch(e){}
14225    },
14226    
14227    /**
14228     * Gets all css rules for the document
14229     * @param {Boolean} refreshCache true to refresh the internal cache
14230     * @return {Object} An object (hash) of rules indexed by selector
14231     */
14232    getRules : function(refreshCache){
14233                 if(rules == null || refreshCache){
14234                         rules = {};
14235                         var ds = doc.styleSheets;
14236                         for(var i =0, len = ds.length; i < len; i++){
14237                             try{
14238                         this.cacheStyleSheet(ds[i]);
14239                     }catch(e){} 
14240                 }
14241                 }
14242                 return rules;
14243         },
14244         
14245         /**
14246     * Gets an an individual CSS rule by selector(s)
14247     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14248     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14249     * @return {CSSRule} The CSS rule or null if one is not found
14250     */
14251    getRule : function(selector, refreshCache){
14252                 var rs = this.getRules(refreshCache);
14253                 if(!(selector instanceof Array)){
14254                     return rs[selector];
14255                 }
14256                 for(var i = 0; i < selector.length; i++){
14257                         if(rs[selector[i]]){
14258                                 return rs[selector[i]];
14259                         }
14260                 }
14261                 return null;
14262         },
14263         
14264         
14265         /**
14266     * Updates a rule property
14267     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14268     * @param {String} property The css property
14269     * @param {String} value The new value for the property
14270     * @return {Boolean} true If a rule was found and updated
14271     */
14272    updateRule : function(selector, property, value){
14273                 if(!(selector instanceof Array)){
14274                         var rule = this.getRule(selector);
14275                         if(rule){
14276                                 rule.style[property.replace(camelRe, camelFn)] = value;
14277                                 return true;
14278                         }
14279                 }else{
14280                         for(var i = 0; i < selector.length; i++){
14281                                 if(this.updateRule(selector[i], property, value)){
14282                                         return true;
14283                                 }
14284                         }
14285                 }
14286                 return false;
14287         }
14288    };   
14289 }();/*
14290  * Based on:
14291  * Ext JS Library 1.1.1
14292  * Copyright(c) 2006-2007, Ext JS, LLC.
14293  *
14294  * Originally Released Under LGPL - original licence link has changed is not relivant.
14295  *
14296  * Fork - LGPL
14297  * <script type="text/javascript">
14298  */
14299
14300  
14301
14302 /**
14303  * @class Roo.util.ClickRepeater
14304  * @extends Roo.util.Observable
14305  * 
14306  * A wrapper class which can be applied to any element. Fires a "click" event while the
14307  * mouse is pressed. The interval between firings may be specified in the config but
14308  * defaults to 10 milliseconds.
14309  * 
14310  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14311  * 
14312  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14313  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14314  * Similar to an autorepeat key delay.
14315  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14316  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14317  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14318  *           "interval" and "delay" are ignored. "immediate" is honored.
14319  * @cfg {Boolean} preventDefault True to prevent the default click event
14320  * @cfg {Boolean} stopDefault True to stop the default click event
14321  * 
14322  * @history
14323  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14324  *     2007-02-02 jvs Renamed to ClickRepeater
14325  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14326  *
14327  *  @constructor
14328  * @param {String/HTMLElement/Element} el The element to listen on
14329  * @param {Object} config
14330  **/
14331 Roo.util.ClickRepeater = function(el, config)
14332 {
14333     this.el = Roo.get(el);
14334     this.el.unselectable();
14335
14336     Roo.apply(this, config);
14337
14338     this.addEvents({
14339     /**
14340      * @event mousedown
14341      * Fires when the mouse button is depressed.
14342      * @param {Roo.util.ClickRepeater} this
14343      */
14344         "mousedown" : true,
14345     /**
14346      * @event click
14347      * Fires on a specified interval during the time the element is pressed.
14348      * @param {Roo.util.ClickRepeater} this
14349      */
14350         "click" : true,
14351     /**
14352      * @event mouseup
14353      * Fires when the mouse key is released.
14354      * @param {Roo.util.ClickRepeater} this
14355      */
14356         "mouseup" : true
14357     });
14358
14359     this.el.on("mousedown", this.handleMouseDown, this);
14360     if(this.preventDefault || this.stopDefault){
14361         this.el.on("click", function(e){
14362             if(this.preventDefault){
14363                 e.preventDefault();
14364             }
14365             if(this.stopDefault){
14366                 e.stopEvent();
14367             }
14368         }, this);
14369     }
14370
14371     // allow inline handler
14372     if(this.handler){
14373         this.on("click", this.handler,  this.scope || this);
14374     }
14375
14376     Roo.util.ClickRepeater.superclass.constructor.call(this);
14377 };
14378
14379 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14380     interval : 20,
14381     delay: 250,
14382     preventDefault : true,
14383     stopDefault : false,
14384     timer : 0,
14385
14386     // private
14387     handleMouseDown : function(){
14388         clearTimeout(this.timer);
14389         this.el.blur();
14390         if(this.pressClass){
14391             this.el.addClass(this.pressClass);
14392         }
14393         this.mousedownTime = new Date();
14394
14395         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14396         this.el.on("mouseout", this.handleMouseOut, this);
14397
14398         this.fireEvent("mousedown", this);
14399         this.fireEvent("click", this);
14400         
14401         this.timer = this.click.defer(this.delay || this.interval, this);
14402     },
14403
14404     // private
14405     click : function(){
14406         this.fireEvent("click", this);
14407         this.timer = this.click.defer(this.getInterval(), this);
14408     },
14409
14410     // private
14411     getInterval: function(){
14412         if(!this.accelerate){
14413             return this.interval;
14414         }
14415         var pressTime = this.mousedownTime.getElapsed();
14416         if(pressTime < 500){
14417             return 400;
14418         }else if(pressTime < 1700){
14419             return 320;
14420         }else if(pressTime < 2600){
14421             return 250;
14422         }else if(pressTime < 3500){
14423             return 180;
14424         }else if(pressTime < 4400){
14425             return 140;
14426         }else if(pressTime < 5300){
14427             return 80;
14428         }else if(pressTime < 6200){
14429             return 50;
14430         }else{
14431             return 10;
14432         }
14433     },
14434
14435     // private
14436     handleMouseOut : function(){
14437         clearTimeout(this.timer);
14438         if(this.pressClass){
14439             this.el.removeClass(this.pressClass);
14440         }
14441         this.el.on("mouseover", this.handleMouseReturn, this);
14442     },
14443
14444     // private
14445     handleMouseReturn : function(){
14446         this.el.un("mouseover", this.handleMouseReturn);
14447         if(this.pressClass){
14448             this.el.addClass(this.pressClass);
14449         }
14450         this.click();
14451     },
14452
14453     // private
14454     handleMouseUp : function(){
14455         clearTimeout(this.timer);
14456         this.el.un("mouseover", this.handleMouseReturn);
14457         this.el.un("mouseout", this.handleMouseOut);
14458         Roo.get(document).un("mouseup", this.handleMouseUp);
14459         this.el.removeClass(this.pressClass);
14460         this.fireEvent("mouseup", this);
14461     }
14462 });/*
14463  * Based on:
14464  * Ext JS Library 1.1.1
14465  * Copyright(c) 2006-2007, Ext JS, LLC.
14466  *
14467  * Originally Released Under LGPL - original licence link has changed is not relivant.
14468  *
14469  * Fork - LGPL
14470  * <script type="text/javascript">
14471  */
14472
14473  
14474 /**
14475  * @class Roo.KeyNav
14476  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14477  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14478  * way to implement custom navigation schemes for any UI component.</p>
14479  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14480  * pageUp, pageDown, del, home, end.  Usage:</p>
14481  <pre><code>
14482 var nav = new Roo.KeyNav("my-element", {
14483     "left" : function(e){
14484         this.moveLeft(e.ctrlKey);
14485     },
14486     "right" : function(e){
14487         this.moveRight(e.ctrlKey);
14488     },
14489     "enter" : function(e){
14490         this.save();
14491     },
14492     scope : this
14493 });
14494 </code></pre>
14495  * @constructor
14496  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14497  * @param {Object} config The config
14498  */
14499 Roo.KeyNav = function(el, config){
14500     this.el = Roo.get(el);
14501     Roo.apply(this, config);
14502     if(!this.disabled){
14503         this.disabled = true;
14504         this.enable();
14505     }
14506 };
14507
14508 Roo.KeyNav.prototype = {
14509     /**
14510      * @cfg {Boolean} disabled
14511      * True to disable this KeyNav instance (defaults to false)
14512      */
14513     disabled : false,
14514     /**
14515      * @cfg {String} defaultEventAction
14516      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14517      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14518      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14519      */
14520     defaultEventAction: "stopEvent",
14521     /**
14522      * @cfg {Boolean} forceKeyDown
14523      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14524      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14525      * handle keydown instead of keypress.
14526      */
14527     forceKeyDown : false,
14528
14529     // private
14530     prepareEvent : function(e){
14531         var k = e.getKey();
14532         var h = this.keyToHandler[k];
14533         //if(h && this[h]){
14534         //    e.stopPropagation();
14535         //}
14536         if(Roo.isSafari && h && k >= 37 && k <= 40){
14537             e.stopEvent();
14538         }
14539     },
14540
14541     // private
14542     relay : function(e){
14543         var k = e.getKey();
14544         var h = this.keyToHandler[k];
14545         if(h && this[h]){
14546             if(this.doRelay(e, this[h], h) !== true){
14547                 e[this.defaultEventAction]();
14548             }
14549         }
14550     },
14551
14552     // private
14553     doRelay : function(e, h, hname){
14554         return h.call(this.scope || this, e);
14555     },
14556
14557     // possible handlers
14558     enter : false,
14559     left : false,
14560     right : false,
14561     up : false,
14562     down : false,
14563     tab : false,
14564     esc : false,
14565     pageUp : false,
14566     pageDown : false,
14567     del : false,
14568     home : false,
14569     end : false,
14570
14571     // quick lookup hash
14572     keyToHandler : {
14573         37 : "left",
14574         39 : "right",
14575         38 : "up",
14576         40 : "down",
14577         33 : "pageUp",
14578         34 : "pageDown",
14579         46 : "del",
14580         36 : "home",
14581         35 : "end",
14582         13 : "enter",
14583         27 : "esc",
14584         9  : "tab"
14585     },
14586
14587         /**
14588          * Enable this KeyNav
14589          */
14590         enable: function(){
14591                 if(this.disabled){
14592             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14593             // the EventObject will normalize Safari automatically
14594             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14595                 this.el.on("keydown", this.relay,  this);
14596             }else{
14597                 this.el.on("keydown", this.prepareEvent,  this);
14598                 this.el.on("keypress", this.relay,  this);
14599             }
14600                     this.disabled = false;
14601                 }
14602         },
14603
14604         /**
14605          * Disable this KeyNav
14606          */
14607         disable: function(){
14608                 if(!this.disabled){
14609                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14610                 this.el.un("keydown", this.relay);
14611             }else{
14612                 this.el.un("keydown", this.prepareEvent);
14613                 this.el.un("keypress", this.relay);
14614             }
14615                     this.disabled = true;
14616                 }
14617         }
14618 };/*
14619  * Based on:
14620  * Ext JS Library 1.1.1
14621  * Copyright(c) 2006-2007, Ext JS, LLC.
14622  *
14623  * Originally Released Under LGPL - original licence link has changed is not relivant.
14624  *
14625  * Fork - LGPL
14626  * <script type="text/javascript">
14627  */
14628
14629  
14630 /**
14631  * @class Roo.KeyMap
14632  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14633  * The constructor accepts the same config object as defined by {@link #addBinding}.
14634  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14635  * combination it will call the function with this signature (if the match is a multi-key
14636  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14637  * A KeyMap can also handle a string representation of keys.<br />
14638  * Usage:
14639  <pre><code>
14640 // map one key by key code
14641 var map = new Roo.KeyMap("my-element", {
14642     key: 13, // or Roo.EventObject.ENTER
14643     fn: myHandler,
14644     scope: myObject
14645 });
14646
14647 // map multiple keys to one action by string
14648 var map = new Roo.KeyMap("my-element", {
14649     key: "a\r\n\t",
14650     fn: myHandler,
14651     scope: myObject
14652 });
14653
14654 // map multiple keys to multiple actions by strings and array of codes
14655 var map = new Roo.KeyMap("my-element", [
14656     {
14657         key: [10,13],
14658         fn: function(){ alert("Return was pressed"); }
14659     }, {
14660         key: "abc",
14661         fn: function(){ alert('a, b or c was pressed'); }
14662     }, {
14663         key: "\t",
14664         ctrl:true,
14665         shift:true,
14666         fn: function(){ alert('Control + shift + tab was pressed.'); }
14667     }
14668 ]);
14669 </code></pre>
14670  * <b>Note: A KeyMap starts enabled</b>
14671  * @constructor
14672  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14673  * @param {Object} config The config (see {@link #addBinding})
14674  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14675  */
14676 Roo.KeyMap = function(el, config, eventName){
14677     this.el  = Roo.get(el);
14678     this.eventName = eventName || "keydown";
14679     this.bindings = [];
14680     if(config){
14681         this.addBinding(config);
14682     }
14683     this.enable();
14684 };
14685
14686 Roo.KeyMap.prototype = {
14687     /**
14688      * True to stop the event from bubbling and prevent the default browser action if the
14689      * key was handled by the KeyMap (defaults to false)
14690      * @type Boolean
14691      */
14692     stopEvent : false,
14693
14694     /**
14695      * Add a new binding to this KeyMap. The following config object properties are supported:
14696      * <pre>
14697 Property    Type             Description
14698 ----------  ---------------  ----------------------------------------------------------------------
14699 key         String/Array     A single keycode or an array of keycodes to handle
14700 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14701 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14702 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14703 fn          Function         The function to call when KeyMap finds the expected key combination
14704 scope       Object           The scope of the callback function
14705 </pre>
14706      *
14707      * Usage:
14708      * <pre><code>
14709 // Create a KeyMap
14710 var map = new Roo.KeyMap(document, {
14711     key: Roo.EventObject.ENTER,
14712     fn: handleKey,
14713     scope: this
14714 });
14715
14716 //Add a new binding to the existing KeyMap later
14717 map.addBinding({
14718     key: 'abc',
14719     shift: true,
14720     fn: handleKey,
14721     scope: this
14722 });
14723 </code></pre>
14724      * @param {Object/Array} config A single KeyMap config or an array of configs
14725      */
14726         addBinding : function(config){
14727         if(config instanceof Array){
14728             for(var i = 0, len = config.length; i < len; i++){
14729                 this.addBinding(config[i]);
14730             }
14731             return;
14732         }
14733         var keyCode = config.key,
14734             shift = config.shift, 
14735             ctrl = config.ctrl, 
14736             alt = config.alt,
14737             fn = config.fn,
14738             scope = config.scope;
14739         if(typeof keyCode == "string"){
14740             var ks = [];
14741             var keyString = keyCode.toUpperCase();
14742             for(var j = 0, len = keyString.length; j < len; j++){
14743                 ks.push(keyString.charCodeAt(j));
14744             }
14745             keyCode = ks;
14746         }
14747         var keyArray = keyCode instanceof Array;
14748         var handler = function(e){
14749             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14750                 var k = e.getKey();
14751                 if(keyArray){
14752                     for(var i = 0, len = keyCode.length; i < len; i++){
14753                         if(keyCode[i] == k){
14754                           if(this.stopEvent){
14755                               e.stopEvent();
14756                           }
14757                           fn.call(scope || window, k, e);
14758                           return;
14759                         }
14760                     }
14761                 }else{
14762                     if(k == keyCode){
14763                         if(this.stopEvent){
14764                            e.stopEvent();
14765                         }
14766                         fn.call(scope || window, k, e);
14767                     }
14768                 }
14769             }
14770         };
14771         this.bindings.push(handler);  
14772         },
14773
14774     /**
14775      * Shorthand for adding a single key listener
14776      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14777      * following options:
14778      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14779      * @param {Function} fn The function to call
14780      * @param {Object} scope (optional) The scope of the function
14781      */
14782     on : function(key, fn, scope){
14783         var keyCode, shift, ctrl, alt;
14784         if(typeof key == "object" && !(key instanceof Array)){
14785             keyCode = key.key;
14786             shift = key.shift;
14787             ctrl = key.ctrl;
14788             alt = key.alt;
14789         }else{
14790             keyCode = key;
14791         }
14792         this.addBinding({
14793             key: keyCode,
14794             shift: shift,
14795             ctrl: ctrl,
14796             alt: alt,
14797             fn: fn,
14798             scope: scope
14799         })
14800     },
14801
14802     // private
14803     handleKeyDown : function(e){
14804             if(this.enabled){ //just in case
14805             var b = this.bindings;
14806             for(var i = 0, len = b.length; i < len; i++){
14807                 b[i].call(this, e);
14808             }
14809             }
14810         },
14811         
14812         /**
14813          * Returns true if this KeyMap is enabled
14814          * @return {Boolean} 
14815          */
14816         isEnabled : function(){
14817             return this.enabled;  
14818         },
14819         
14820         /**
14821          * Enables this KeyMap
14822          */
14823         enable: function(){
14824                 if(!this.enabled){
14825                     this.el.on(this.eventName, this.handleKeyDown, this);
14826                     this.enabled = true;
14827                 }
14828         },
14829
14830         /**
14831          * Disable this KeyMap
14832          */
14833         disable: function(){
14834                 if(this.enabled){
14835                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14836                     this.enabled = false;
14837                 }
14838         }
14839 };/*
14840  * Based on:
14841  * Ext JS Library 1.1.1
14842  * Copyright(c) 2006-2007, Ext JS, LLC.
14843  *
14844  * Originally Released Under LGPL - original licence link has changed is not relivant.
14845  *
14846  * Fork - LGPL
14847  * <script type="text/javascript">
14848  */
14849
14850  
14851 /**
14852  * @class Roo.util.TextMetrics
14853  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14854  * wide, in pixels, a given block of text will be.
14855  * @singleton
14856  */
14857 Roo.util.TextMetrics = function(){
14858     var shared;
14859     return {
14860         /**
14861          * Measures the size of the specified text
14862          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14863          * that can affect the size of the rendered text
14864          * @param {String} text The text to measure
14865          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14866          * in order to accurately measure the text height
14867          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14868          */
14869         measure : function(el, text, fixedWidth){
14870             if(!shared){
14871                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14872             }
14873             shared.bind(el);
14874             shared.setFixedWidth(fixedWidth || 'auto');
14875             return shared.getSize(text);
14876         },
14877
14878         /**
14879          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14880          * the overhead of multiple calls to initialize the style properties on each measurement.
14881          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14882          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14883          * in order to accurately measure the text height
14884          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14885          */
14886         createInstance : function(el, fixedWidth){
14887             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14888         }
14889     };
14890 }();
14891
14892  
14893
14894 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14895     var ml = new Roo.Element(document.createElement('div'));
14896     document.body.appendChild(ml.dom);
14897     ml.position('absolute');
14898     ml.setLeftTop(-1000, -1000);
14899     ml.hide();
14900
14901     if(fixedWidth){
14902         ml.setWidth(fixedWidth);
14903     }
14904      
14905     var instance = {
14906         /**
14907          * Returns the size of the specified text based on the internal element's style and width properties
14908          * @memberOf Roo.util.TextMetrics.Instance#
14909          * @param {String} text The text to measure
14910          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14911          */
14912         getSize : function(text){
14913             ml.update(text);
14914             var s = ml.getSize();
14915             ml.update('');
14916             return s;
14917         },
14918
14919         /**
14920          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14921          * that can affect the size of the rendered text
14922          * @memberOf Roo.util.TextMetrics.Instance#
14923          * @param {String/HTMLElement} el The element, dom node or id
14924          */
14925         bind : function(el){
14926             ml.setStyle(
14927                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14928             );
14929         },
14930
14931         /**
14932          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14933          * to set a fixed width in order to accurately measure the text height.
14934          * @memberOf Roo.util.TextMetrics.Instance#
14935          * @param {Number} width The width to set on the element
14936          */
14937         setFixedWidth : function(width){
14938             ml.setWidth(width);
14939         },
14940
14941         /**
14942          * Returns the measured width of the specified text
14943          * @memberOf Roo.util.TextMetrics.Instance#
14944          * @param {String} text The text to measure
14945          * @return {Number} width The width in pixels
14946          */
14947         getWidth : function(text){
14948             ml.dom.style.width = 'auto';
14949             return this.getSize(text).width;
14950         },
14951
14952         /**
14953          * Returns the measured height of the specified text.  For multiline text, be sure to call
14954          * {@link #setFixedWidth} if necessary.
14955          * @memberOf Roo.util.TextMetrics.Instance#
14956          * @param {String} text The text to measure
14957          * @return {Number} height The height in pixels
14958          */
14959         getHeight : function(text){
14960             return this.getSize(text).height;
14961         }
14962     };
14963
14964     instance.bind(bindTo);
14965
14966     return instance;
14967 };
14968
14969 // backwards compat
14970 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14971  * Based on:
14972  * Ext JS Library 1.1.1
14973  * Copyright(c) 2006-2007, Ext JS, LLC.
14974  *
14975  * Originally Released Under LGPL - original licence link has changed is not relivant.
14976  *
14977  * Fork - LGPL
14978  * <script type="text/javascript">
14979  */
14980
14981 /**
14982  * @class Roo.state.Provider
14983  * Abstract base class for state provider implementations. This class provides methods
14984  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14985  * Provider interface.
14986  */
14987 Roo.state.Provider = function(){
14988     /**
14989      * @event statechange
14990      * Fires when a state change occurs.
14991      * @param {Provider} this This state provider
14992      * @param {String} key The state key which was changed
14993      * @param {String} value The encoded value for the state
14994      */
14995     this.addEvents({
14996         "statechange": true
14997     });
14998     this.state = {};
14999     Roo.state.Provider.superclass.constructor.call(this);
15000 };
15001 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15002     /**
15003      * Returns the current value for a key
15004      * @param {String} name The key name
15005      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15006      * @return {Mixed} The state data
15007      */
15008     get : function(name, defaultValue){
15009         return typeof this.state[name] == "undefined" ?
15010             defaultValue : this.state[name];
15011     },
15012     
15013     /**
15014      * Clears a value from the state
15015      * @param {String} name The key name
15016      */
15017     clear : function(name){
15018         delete this.state[name];
15019         this.fireEvent("statechange", this, name, null);
15020     },
15021     
15022     /**
15023      * Sets the value for a key
15024      * @param {String} name The key name
15025      * @param {Mixed} value The value to set
15026      */
15027     set : function(name, value){
15028         this.state[name] = value;
15029         this.fireEvent("statechange", this, name, value);
15030     },
15031     
15032     /**
15033      * Decodes a string previously encoded with {@link #encodeValue}.
15034      * @param {String} value The value to decode
15035      * @return {Mixed} The decoded value
15036      */
15037     decodeValue : function(cookie){
15038         var re = /^(a|n|d|b|s|o)\:(.*)$/;
15039         var matches = re.exec(unescape(cookie));
15040         if(!matches || !matches[1]) {
15041             return; // non state cookie
15042         }
15043         var type = matches[1];
15044         var v = matches[2];
15045         switch(type){
15046             case "n":
15047                 return parseFloat(v);
15048             case "d":
15049                 return new Date(Date.parse(v));
15050             case "b":
15051                 return (v == "1");
15052             case "a":
15053                 var all = [];
15054                 var values = v.split("^");
15055                 for(var i = 0, len = values.length; i < len; i++){
15056                     all.push(this.decodeValue(values[i]));
15057                 }
15058                 return all;
15059            case "o":
15060                 var all = {};
15061                 var values = v.split("^");
15062                 for(var i = 0, len = values.length; i < len; i++){
15063                     var kv = values[i].split("=");
15064                     all[kv[0]] = this.decodeValue(kv[1]);
15065                 }
15066                 return all;
15067            default:
15068                 return v;
15069         }
15070     },
15071     
15072     /**
15073      * Encodes a value including type information.  Decode with {@link #decodeValue}.
15074      * @param {Mixed} value The value to encode
15075      * @return {String} The encoded value
15076      */
15077     encodeValue : function(v){
15078         var enc;
15079         if(typeof v == "number"){
15080             enc = "n:" + v;
15081         }else if(typeof v == "boolean"){
15082             enc = "b:" + (v ? "1" : "0");
15083         }else if(v instanceof Date){
15084             enc = "d:" + v.toGMTString();
15085         }else if(v instanceof Array){
15086             var flat = "";
15087             for(var i = 0, len = v.length; i < len; i++){
15088                 flat += this.encodeValue(v[i]);
15089                 if(i != len-1) {
15090                     flat += "^";
15091                 }
15092             }
15093             enc = "a:" + flat;
15094         }else if(typeof v == "object"){
15095             var flat = "";
15096             for(var key in v){
15097                 if(typeof v[key] != "function"){
15098                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15099                 }
15100             }
15101             enc = "o:" + flat.substring(0, flat.length-1);
15102         }else{
15103             enc = "s:" + v;
15104         }
15105         return escape(enc);        
15106     }
15107 });
15108
15109 /*
15110  * Based on:
15111  * Ext JS Library 1.1.1
15112  * Copyright(c) 2006-2007, Ext JS, LLC.
15113  *
15114  * Originally Released Under LGPL - original licence link has changed is not relivant.
15115  *
15116  * Fork - LGPL
15117  * <script type="text/javascript">
15118  */
15119 /**
15120  * @class Roo.state.Manager
15121  * This is the global state manager. By default all components that are "state aware" check this class
15122  * for state information if you don't pass them a custom state provider. In order for this class
15123  * to be useful, it must be initialized with a provider when your application initializes.
15124  <pre><code>
15125 // in your initialization function
15126 init : function(){
15127    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15128    ...
15129    // supposed you have a {@link Roo.BorderLayout}
15130    var layout = new Roo.BorderLayout(...);
15131    layout.restoreState();
15132    // or a {Roo.BasicDialog}
15133    var dialog = new Roo.BasicDialog(...);
15134    dialog.restoreState();
15135  </code></pre>
15136  * @singleton
15137  */
15138 Roo.state.Manager = function(){
15139     var provider = new Roo.state.Provider();
15140     
15141     return {
15142         /**
15143          * Configures the default state provider for your application
15144          * @param {Provider} stateProvider The state provider to set
15145          */
15146         setProvider : function(stateProvider){
15147             provider = stateProvider;
15148         },
15149         
15150         /**
15151          * Returns the current value for a key
15152          * @param {String} name The key name
15153          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15154          * @return {Mixed} The state data
15155          */
15156         get : function(key, defaultValue){
15157             return provider.get(key, defaultValue);
15158         },
15159         
15160         /**
15161          * Sets the value for a key
15162          * @param {String} name The key name
15163          * @param {Mixed} value The state data
15164          */
15165          set : function(key, value){
15166             provider.set(key, value);
15167         },
15168         
15169         /**
15170          * Clears a value from the state
15171          * @param {String} name The key name
15172          */
15173         clear : function(key){
15174             provider.clear(key);
15175         },
15176         
15177         /**
15178          * Gets the currently configured state provider
15179          * @return {Provider} The state provider
15180          */
15181         getProvider : function(){
15182             return provider;
15183         }
15184     };
15185 }();
15186 /*
15187  * Based on:
15188  * Ext JS Library 1.1.1
15189  * Copyright(c) 2006-2007, Ext JS, LLC.
15190  *
15191  * Originally Released Under LGPL - original licence link has changed is not relivant.
15192  *
15193  * Fork - LGPL
15194  * <script type="text/javascript">
15195  */
15196 /**
15197  * @class Roo.state.CookieProvider
15198  * @extends Roo.state.Provider
15199  * The default Provider implementation which saves state via cookies.
15200  * <br />Usage:
15201  <pre><code>
15202    var cp = new Roo.state.CookieProvider({
15203        path: "/cgi-bin/",
15204        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15205        domain: "roojs.com"
15206    })
15207    Roo.state.Manager.setProvider(cp);
15208  </code></pre>
15209  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15210  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15211  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15212  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15213  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15214  * domain the page is running on including the 'www' like 'www.roojs.com')
15215  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15216  * @constructor
15217  * Create a new CookieProvider
15218  * @param {Object} config The configuration object
15219  */
15220 Roo.state.CookieProvider = function(config){
15221     Roo.state.CookieProvider.superclass.constructor.call(this);
15222     this.path = "/";
15223     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15224     this.domain = null;
15225     this.secure = false;
15226     Roo.apply(this, config);
15227     this.state = this.readCookies();
15228 };
15229
15230 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15231     // private
15232     set : function(name, value){
15233         if(typeof value == "undefined" || value === null){
15234             this.clear(name);
15235             return;
15236         }
15237         this.setCookie(name, value);
15238         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15239     },
15240
15241     // private
15242     clear : function(name){
15243         this.clearCookie(name);
15244         Roo.state.CookieProvider.superclass.clear.call(this, name);
15245     },
15246
15247     // private
15248     readCookies : function(){
15249         var cookies = {};
15250         var c = document.cookie + ";";
15251         var re = /\s?(.*?)=(.*?);/g;
15252         var matches;
15253         while((matches = re.exec(c)) != null){
15254             var name = matches[1];
15255             var value = matches[2];
15256             if(name && name.substring(0,3) == "ys-"){
15257                 cookies[name.substr(3)] = this.decodeValue(value);
15258             }
15259         }
15260         return cookies;
15261     },
15262
15263     // private
15264     setCookie : function(name, value){
15265         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15266            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15267            ((this.path == null) ? "" : ("; path=" + this.path)) +
15268            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15269            ((this.secure == true) ? "; secure" : "");
15270     },
15271
15272     // private
15273     clearCookie : function(name){
15274         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15275            ((this.path == null) ? "" : ("; path=" + this.path)) +
15276            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15277            ((this.secure == true) ? "; secure" : "");
15278     }
15279 });/*
15280  * Based on:
15281  * Ext JS Library 1.1.1
15282  * Copyright(c) 2006-2007, Ext JS, LLC.
15283  *
15284  * Originally Released Under LGPL - original licence link has changed is not relivant.
15285  *
15286  * Fork - LGPL
15287  * <script type="text/javascript">
15288  */
15289  
15290
15291 /**
15292  * @class Roo.ComponentMgr
15293  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15294  * @singleton
15295  */
15296 Roo.ComponentMgr = function(){
15297     var all = new Roo.util.MixedCollection();
15298
15299     return {
15300         /**
15301          * Registers a component.
15302          * @param {Roo.Component} c The component
15303          */
15304         register : function(c){
15305             all.add(c);
15306         },
15307
15308         /**
15309          * Unregisters a component.
15310          * @param {Roo.Component} c The component
15311          */
15312         unregister : function(c){
15313             all.remove(c);
15314         },
15315
15316         /**
15317          * Returns a component by id
15318          * @param {String} id The component id
15319          */
15320         get : function(id){
15321             return all.get(id);
15322         },
15323
15324         /**
15325          * Registers a function that will be called when a specified component is added to ComponentMgr
15326          * @param {String} id The component id
15327          * @param {Funtction} fn The callback function
15328          * @param {Object} scope The scope of the callback
15329          */
15330         onAvailable : function(id, fn, scope){
15331             all.on("add", function(index, o){
15332                 if(o.id == id){
15333                     fn.call(scope || o, o);
15334                     all.un("add", fn, scope);
15335                 }
15336             });
15337         }
15338     };
15339 }();/*
15340  * Based on:
15341  * Ext JS Library 1.1.1
15342  * Copyright(c) 2006-2007, Ext JS, LLC.
15343  *
15344  * Originally Released Under LGPL - original licence link has changed is not relivant.
15345  *
15346  * Fork - LGPL
15347  * <script type="text/javascript">
15348  */
15349  
15350 /**
15351  * @class Roo.Component
15352  * @extends Roo.util.Observable
15353  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15354  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15355  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15356  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15357  * All visual components (widgets) that require rendering into a layout should subclass Component.
15358  * @constructor
15359  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15360  * 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
15361  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15362  */
15363 Roo.Component = function(config){
15364     config = config || {};
15365     if(config.tagName || config.dom || typeof config == "string"){ // element object
15366         config = {el: config, id: config.id || config};
15367     }
15368     this.initialConfig = config;
15369
15370     Roo.apply(this, config);
15371     this.addEvents({
15372         /**
15373          * @event disable
15374          * Fires after the component is disabled.
15375              * @param {Roo.Component} this
15376              */
15377         disable : true,
15378         /**
15379          * @event enable
15380          * Fires after the component is enabled.
15381              * @param {Roo.Component} this
15382              */
15383         enable : true,
15384         /**
15385          * @event beforeshow
15386          * Fires before the component is shown.  Return false to stop the show.
15387              * @param {Roo.Component} this
15388              */
15389         beforeshow : true,
15390         /**
15391          * @event show
15392          * Fires after the component is shown.
15393              * @param {Roo.Component} this
15394              */
15395         show : true,
15396         /**
15397          * @event beforehide
15398          * Fires before the component is hidden. Return false to stop the hide.
15399              * @param {Roo.Component} this
15400              */
15401         beforehide : true,
15402         /**
15403          * @event hide
15404          * Fires after the component is hidden.
15405              * @param {Roo.Component} this
15406              */
15407         hide : true,
15408         /**
15409          * @event beforerender
15410          * Fires before the component is rendered. Return false to stop the render.
15411              * @param {Roo.Component} this
15412              */
15413         beforerender : true,
15414         /**
15415          * @event render
15416          * Fires after the component is rendered.
15417              * @param {Roo.Component} this
15418              */
15419         render : true,
15420         /**
15421          * @event beforedestroy
15422          * Fires before the component is destroyed. Return false to stop the destroy.
15423              * @param {Roo.Component} this
15424              */
15425         beforedestroy : true,
15426         /**
15427          * @event destroy
15428          * Fires after the component is destroyed.
15429              * @param {Roo.Component} this
15430              */
15431         destroy : true
15432     });
15433     if(!this.id){
15434         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15435     }
15436     Roo.ComponentMgr.register(this);
15437     Roo.Component.superclass.constructor.call(this);
15438     this.initComponent();
15439     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15440         this.render(this.renderTo);
15441         delete this.renderTo;
15442     }
15443 };
15444
15445 /** @private */
15446 Roo.Component.AUTO_ID = 1000;
15447
15448 Roo.extend(Roo.Component, Roo.util.Observable, {
15449     /**
15450      * @scope Roo.Component.prototype
15451      * @type {Boolean}
15452      * true if this component is hidden. Read-only.
15453      */
15454     hidden : false,
15455     /**
15456      * @type {Boolean}
15457      * true if this component is disabled. Read-only.
15458      */
15459     disabled : false,
15460     /**
15461      * @type {Boolean}
15462      * true if this component has been rendered. Read-only.
15463      */
15464     rendered : false,
15465     
15466     /** @cfg {String} disableClass
15467      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15468      */
15469     disabledClass : "x-item-disabled",
15470         /** @cfg {Boolean} allowDomMove
15471          * Whether the component can move the Dom node when rendering (defaults to true).
15472          */
15473     allowDomMove : true,
15474     /** @cfg {String} hideMode (display|visibility)
15475      * How this component should hidden. Supported values are
15476      * "visibility" (css visibility), "offsets" (negative offset position) and
15477      * "display" (css display) - defaults to "display".
15478      */
15479     hideMode: 'display',
15480
15481     /** @private */
15482     ctype : "Roo.Component",
15483
15484     /**
15485      * @cfg {String} actionMode 
15486      * which property holds the element that used for  hide() / show() / disable() / enable()
15487      * default is 'el' for forms you probably want to set this to fieldEl 
15488      */
15489     actionMode : "el",
15490
15491     /** @private */
15492     getActionEl : function(){
15493         return this[this.actionMode];
15494     },
15495
15496     initComponent : Roo.emptyFn,
15497     /**
15498      * If this is a lazy rendering component, render it to its container element.
15499      * @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.
15500      */
15501     render : function(container, position){
15502         
15503         if(this.rendered){
15504             return this;
15505         }
15506         
15507         if(this.fireEvent("beforerender", this) === false){
15508             return false;
15509         }
15510         
15511         if(!container && this.el){
15512             this.el = Roo.get(this.el);
15513             container = this.el.dom.parentNode;
15514             this.allowDomMove = false;
15515         }
15516         this.container = Roo.get(container);
15517         this.rendered = true;
15518         if(position !== undefined){
15519             if(typeof position == 'number'){
15520                 position = this.container.dom.childNodes[position];
15521             }else{
15522                 position = Roo.getDom(position);
15523             }
15524         }
15525         this.onRender(this.container, position || null);
15526         if(this.cls){
15527             this.el.addClass(this.cls);
15528             delete this.cls;
15529         }
15530         if(this.style){
15531             this.el.applyStyles(this.style);
15532             delete this.style;
15533         }
15534         this.fireEvent("render", this);
15535         this.afterRender(this.container);
15536         if(this.hidden){
15537             this.hide();
15538         }
15539         if(this.disabled){
15540             this.disable();
15541         }
15542
15543         return this;
15544         
15545     },
15546
15547     /** @private */
15548     // default function is not really useful
15549     onRender : function(ct, position){
15550         if(this.el){
15551             this.el = Roo.get(this.el);
15552             if(this.allowDomMove !== false){
15553                 ct.dom.insertBefore(this.el.dom, position);
15554             }
15555         }
15556     },
15557
15558     /** @private */
15559     getAutoCreate : function(){
15560         var cfg = typeof this.autoCreate == "object" ?
15561                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15562         if(this.id && !cfg.id){
15563             cfg.id = this.id;
15564         }
15565         return cfg;
15566     },
15567
15568     /** @private */
15569     afterRender : Roo.emptyFn,
15570
15571     /**
15572      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15573      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15574      */
15575     destroy : function(){
15576         if(this.fireEvent("beforedestroy", this) !== false){
15577             this.purgeListeners();
15578             this.beforeDestroy();
15579             if(this.rendered){
15580                 this.el.removeAllListeners();
15581                 this.el.remove();
15582                 if(this.actionMode == "container"){
15583                     this.container.remove();
15584                 }
15585             }
15586             this.onDestroy();
15587             Roo.ComponentMgr.unregister(this);
15588             this.fireEvent("destroy", this);
15589         }
15590     },
15591
15592         /** @private */
15593     beforeDestroy : function(){
15594
15595     },
15596
15597         /** @private */
15598         onDestroy : function(){
15599
15600     },
15601
15602     /**
15603      * Returns the underlying {@link Roo.Element}.
15604      * @return {Roo.Element} The element
15605      */
15606     getEl : function(){
15607         return this.el;
15608     },
15609
15610     /**
15611      * Returns the id of this component.
15612      * @return {String}
15613      */
15614     getId : function(){
15615         return this.id;
15616     },
15617
15618     /**
15619      * Try to focus this component.
15620      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15621      * @return {Roo.Component} this
15622      */
15623     focus : function(selectText){
15624         if(this.rendered){
15625             this.el.focus();
15626             if(selectText === true){
15627                 this.el.dom.select();
15628             }
15629         }
15630         return this;
15631     },
15632
15633     /** @private */
15634     blur : function(){
15635         if(this.rendered){
15636             this.el.blur();
15637         }
15638         return this;
15639     },
15640
15641     /**
15642      * Disable this component.
15643      * @return {Roo.Component} this
15644      */
15645     disable : function(){
15646         if(this.rendered){
15647             this.onDisable();
15648         }
15649         this.disabled = true;
15650         this.fireEvent("disable", this);
15651         return this;
15652     },
15653
15654         // private
15655     onDisable : function(){
15656         this.getActionEl().addClass(this.disabledClass);
15657         this.el.dom.disabled = true;
15658     },
15659
15660     /**
15661      * Enable this component.
15662      * @return {Roo.Component} this
15663      */
15664     enable : function(){
15665         if(this.rendered){
15666             this.onEnable();
15667         }
15668         this.disabled = false;
15669         this.fireEvent("enable", this);
15670         return this;
15671     },
15672
15673         // private
15674     onEnable : function(){
15675         this.getActionEl().removeClass(this.disabledClass);
15676         this.el.dom.disabled = false;
15677     },
15678
15679     /**
15680      * Convenience function for setting disabled/enabled by boolean.
15681      * @param {Boolean} disabled
15682      */
15683     setDisabled : function(disabled){
15684         this[disabled ? "disable" : "enable"]();
15685     },
15686
15687     /**
15688      * Show this component.
15689      * @return {Roo.Component} this
15690      */
15691     show: function(){
15692         if(this.fireEvent("beforeshow", this) !== false){
15693             this.hidden = false;
15694             if(this.rendered){
15695                 this.onShow();
15696             }
15697             this.fireEvent("show", this);
15698         }
15699         return this;
15700     },
15701
15702     // private
15703     onShow : function(){
15704         var ae = this.getActionEl();
15705         if(this.hideMode == 'visibility'){
15706             ae.dom.style.visibility = "visible";
15707         }else if(this.hideMode == 'offsets'){
15708             ae.removeClass('x-hidden');
15709         }else{
15710             ae.dom.style.display = "";
15711         }
15712     },
15713
15714     /**
15715      * Hide this component.
15716      * @return {Roo.Component} this
15717      */
15718     hide: function(){
15719         if(this.fireEvent("beforehide", this) !== false){
15720             this.hidden = true;
15721             if(this.rendered){
15722                 this.onHide();
15723             }
15724             this.fireEvent("hide", this);
15725         }
15726         return this;
15727     },
15728
15729     // private
15730     onHide : function(){
15731         var ae = this.getActionEl();
15732         if(this.hideMode == 'visibility'){
15733             ae.dom.style.visibility = "hidden";
15734         }else if(this.hideMode == 'offsets'){
15735             ae.addClass('x-hidden');
15736         }else{
15737             ae.dom.style.display = "none";
15738         }
15739     },
15740
15741     /**
15742      * Convenience function to hide or show this component by boolean.
15743      * @param {Boolean} visible True to show, false to hide
15744      * @return {Roo.Component} this
15745      */
15746     setVisible: function(visible){
15747         if(visible) {
15748             this.show();
15749         }else{
15750             this.hide();
15751         }
15752         return this;
15753     },
15754
15755     /**
15756      * Returns true if this component is visible.
15757      */
15758     isVisible : function(){
15759         return this.getActionEl().isVisible();
15760     },
15761
15762     cloneConfig : function(overrides){
15763         overrides = overrides || {};
15764         var id = overrides.id || Roo.id();
15765         var cfg = Roo.applyIf(overrides, this.initialConfig);
15766         cfg.id = id; // prevent dup id
15767         return new this.constructor(cfg);
15768     }
15769 });/*
15770  * Based on:
15771  * Ext JS Library 1.1.1
15772  * Copyright(c) 2006-2007, Ext JS, LLC.
15773  *
15774  * Originally Released Under LGPL - original licence link has changed is not relivant.
15775  *
15776  * Fork - LGPL
15777  * <script type="text/javascript">
15778  */
15779
15780 /**
15781  * @class Roo.BoxComponent
15782  * @extends Roo.Component
15783  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15784  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15785  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15786  * layout containers.
15787  * @constructor
15788  * @param {Roo.Element/String/Object} config The configuration options.
15789  */
15790 Roo.BoxComponent = function(config){
15791     Roo.Component.call(this, config);
15792     this.addEvents({
15793         /**
15794          * @event resize
15795          * Fires after the component is resized.
15796              * @param {Roo.Component} this
15797              * @param {Number} adjWidth The box-adjusted width that was set
15798              * @param {Number} adjHeight The box-adjusted height that was set
15799              * @param {Number} rawWidth The width that was originally specified
15800              * @param {Number} rawHeight The height that was originally specified
15801              */
15802         resize : true,
15803         /**
15804          * @event move
15805          * Fires after the component is moved.
15806              * @param {Roo.Component} this
15807              * @param {Number} x The new x position
15808              * @param {Number} y The new y position
15809              */
15810         move : true
15811     });
15812 };
15813
15814 Roo.extend(Roo.BoxComponent, Roo.Component, {
15815     // private, set in afterRender to signify that the component has been rendered
15816     boxReady : false,
15817     // private, used to defer height settings to subclasses
15818     deferHeight: false,
15819     /** @cfg {Number} width
15820      * width (optional) size of component
15821      */
15822      /** @cfg {Number} height
15823      * height (optional) size of component
15824      */
15825      
15826     /**
15827      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15828      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15829      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15830      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15831      * @return {Roo.BoxComponent} this
15832      */
15833     setSize : function(w, h){
15834         // support for standard size objects
15835         if(typeof w == 'object'){
15836             h = w.height;
15837             w = w.width;
15838         }
15839         // not rendered
15840         if(!this.boxReady){
15841             this.width = w;
15842             this.height = h;
15843             return this;
15844         }
15845
15846         // prevent recalcs when not needed
15847         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15848             return this;
15849         }
15850         this.lastSize = {width: w, height: h};
15851
15852         var adj = this.adjustSize(w, h);
15853         var aw = adj.width, ah = adj.height;
15854         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15855             var rz = this.getResizeEl();
15856             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15857                 rz.setSize(aw, ah);
15858             }else if(!this.deferHeight && ah !== undefined){
15859                 rz.setHeight(ah);
15860             }else if(aw !== undefined){
15861                 rz.setWidth(aw);
15862             }
15863             this.onResize(aw, ah, w, h);
15864             this.fireEvent('resize', this, aw, ah, w, h);
15865         }
15866         return this;
15867     },
15868
15869     /**
15870      * Gets the current size of the component's underlying element.
15871      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15872      */
15873     getSize : function(){
15874         return this.el.getSize();
15875     },
15876
15877     /**
15878      * Gets the current XY position of the component's underlying element.
15879      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15880      * @return {Array} The XY position of the element (e.g., [100, 200])
15881      */
15882     getPosition : function(local){
15883         if(local === true){
15884             return [this.el.getLeft(true), this.el.getTop(true)];
15885         }
15886         return this.xy || this.el.getXY();
15887     },
15888
15889     /**
15890      * Gets the current box measurements of the component's underlying element.
15891      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15892      * @returns {Object} box An object in the format {x, y, width, height}
15893      */
15894     getBox : function(local){
15895         var s = this.el.getSize();
15896         if(local){
15897             s.x = this.el.getLeft(true);
15898             s.y = this.el.getTop(true);
15899         }else{
15900             var xy = this.xy || this.el.getXY();
15901             s.x = xy[0];
15902             s.y = xy[1];
15903         }
15904         return s;
15905     },
15906
15907     /**
15908      * Sets the current box measurements of the component's underlying element.
15909      * @param {Object} box An object in the format {x, y, width, height}
15910      * @returns {Roo.BoxComponent} this
15911      */
15912     updateBox : function(box){
15913         this.setSize(box.width, box.height);
15914         this.setPagePosition(box.x, box.y);
15915         return this;
15916     },
15917
15918     // protected
15919     getResizeEl : function(){
15920         return this.resizeEl || this.el;
15921     },
15922
15923     // protected
15924     getPositionEl : function(){
15925         return this.positionEl || this.el;
15926     },
15927
15928     /**
15929      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15930      * This method fires the move event.
15931      * @param {Number} left The new left
15932      * @param {Number} top The new top
15933      * @returns {Roo.BoxComponent} this
15934      */
15935     setPosition : function(x, y){
15936         this.x = x;
15937         this.y = y;
15938         if(!this.boxReady){
15939             return this;
15940         }
15941         var adj = this.adjustPosition(x, y);
15942         var ax = adj.x, ay = adj.y;
15943
15944         var el = this.getPositionEl();
15945         if(ax !== undefined || ay !== undefined){
15946             if(ax !== undefined && ay !== undefined){
15947                 el.setLeftTop(ax, ay);
15948             }else if(ax !== undefined){
15949                 el.setLeft(ax);
15950             }else if(ay !== undefined){
15951                 el.setTop(ay);
15952             }
15953             this.onPosition(ax, ay);
15954             this.fireEvent('move', this, ax, ay);
15955         }
15956         return this;
15957     },
15958
15959     /**
15960      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15961      * This method fires the move event.
15962      * @param {Number} x The new x position
15963      * @param {Number} y The new y position
15964      * @returns {Roo.BoxComponent} this
15965      */
15966     setPagePosition : function(x, y){
15967         this.pageX = x;
15968         this.pageY = y;
15969         if(!this.boxReady){
15970             return;
15971         }
15972         if(x === undefined || y === undefined){ // cannot translate undefined points
15973             return;
15974         }
15975         var p = this.el.translatePoints(x, y);
15976         this.setPosition(p.left, p.top);
15977         return this;
15978     },
15979
15980     // private
15981     onRender : function(ct, position){
15982         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15983         if(this.resizeEl){
15984             this.resizeEl = Roo.get(this.resizeEl);
15985         }
15986         if(this.positionEl){
15987             this.positionEl = Roo.get(this.positionEl);
15988         }
15989     },
15990
15991     // private
15992     afterRender : function(){
15993         Roo.BoxComponent.superclass.afterRender.call(this);
15994         this.boxReady = true;
15995         this.setSize(this.width, this.height);
15996         if(this.x || this.y){
15997             this.setPosition(this.x, this.y);
15998         }
15999         if(this.pageX || this.pageY){
16000             this.setPagePosition(this.pageX, this.pageY);
16001         }
16002     },
16003
16004     /**
16005      * Force the component's size to recalculate based on the underlying element's current height and width.
16006      * @returns {Roo.BoxComponent} this
16007      */
16008     syncSize : function(){
16009         delete this.lastSize;
16010         this.setSize(this.el.getWidth(), this.el.getHeight());
16011         return this;
16012     },
16013
16014     /**
16015      * Called after the component is resized, this method is empty by default but can be implemented by any
16016      * subclass that needs to perform custom logic after a resize occurs.
16017      * @param {Number} adjWidth The box-adjusted width that was set
16018      * @param {Number} adjHeight The box-adjusted height that was set
16019      * @param {Number} rawWidth The width that was originally specified
16020      * @param {Number} rawHeight The height that was originally specified
16021      */
16022     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16023
16024     },
16025
16026     /**
16027      * Called after the component is moved, this method is empty by default but can be implemented by any
16028      * subclass that needs to perform custom logic after a move occurs.
16029      * @param {Number} x The new x position
16030      * @param {Number} y The new y position
16031      */
16032     onPosition : function(x, y){
16033
16034     },
16035
16036     // private
16037     adjustSize : function(w, h){
16038         if(this.autoWidth){
16039             w = 'auto';
16040         }
16041         if(this.autoHeight){
16042             h = 'auto';
16043         }
16044         return {width : w, height: h};
16045     },
16046
16047     // private
16048     adjustPosition : function(x, y){
16049         return {x : x, y: y};
16050     }
16051 });/*
16052  * Based on:
16053  * Ext JS Library 1.1.1
16054  * Copyright(c) 2006-2007, Ext JS, LLC.
16055  *
16056  * Originally Released Under LGPL - original licence link has changed is not relivant.
16057  *
16058  * Fork - LGPL
16059  * <script type="text/javascript">
16060  */
16061  (function(){ 
16062 /**
16063  * @class Roo.Layer
16064  * @extends Roo.Element
16065  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16066  * automatic maintaining of shadow/shim positions.
16067  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16068  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16069  * you can pass a string with a CSS class name. False turns off the shadow.
16070  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16071  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16072  * @cfg {String} cls CSS class to add to the element
16073  * @cfg {Number} zindex Starting z-index (defaults to 11000)
16074  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16075  * @constructor
16076  * @param {Object} config An object with config options.
16077  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16078  */
16079
16080 Roo.Layer = function(config, existingEl){
16081     config = config || {};
16082     var dh = Roo.DomHelper;
16083     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16084     if(existingEl){
16085         this.dom = Roo.getDom(existingEl);
16086     }
16087     if(!this.dom){
16088         var o = config.dh || {tag: "div", cls: "x-layer"};
16089         this.dom = dh.append(pel, o);
16090     }
16091     if(config.cls){
16092         this.addClass(config.cls);
16093     }
16094     this.constrain = config.constrain !== false;
16095     this.visibilityMode = Roo.Element.VISIBILITY;
16096     if(config.id){
16097         this.id = this.dom.id = config.id;
16098     }else{
16099         this.id = Roo.id(this.dom);
16100     }
16101     this.zindex = config.zindex || this.getZIndex();
16102     this.position("absolute", this.zindex);
16103     if(config.shadow){
16104         this.shadowOffset = config.shadowOffset || 4;
16105         this.shadow = new Roo.Shadow({
16106             offset : this.shadowOffset,
16107             mode : config.shadow
16108         });
16109     }else{
16110         this.shadowOffset = 0;
16111     }
16112     this.useShim = config.shim !== false && Roo.useShims;
16113     this.useDisplay = config.useDisplay;
16114     this.hide();
16115 };
16116
16117 var supr = Roo.Element.prototype;
16118
16119 // shims are shared among layer to keep from having 100 iframes
16120 var shims = [];
16121
16122 Roo.extend(Roo.Layer, Roo.Element, {
16123
16124     getZIndex : function(){
16125         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16126     },
16127
16128     getShim : function(){
16129         if(!this.useShim){
16130             return null;
16131         }
16132         if(this.shim){
16133             return this.shim;
16134         }
16135         var shim = shims.shift();
16136         if(!shim){
16137             shim = this.createShim();
16138             shim.enableDisplayMode('block');
16139             shim.dom.style.display = 'none';
16140             shim.dom.style.visibility = 'visible';
16141         }
16142         var pn = this.dom.parentNode;
16143         if(shim.dom.parentNode != pn){
16144             pn.insertBefore(shim.dom, this.dom);
16145         }
16146         shim.setStyle('z-index', this.getZIndex()-2);
16147         this.shim = shim;
16148         return shim;
16149     },
16150
16151     hideShim : function(){
16152         if(this.shim){
16153             this.shim.setDisplayed(false);
16154             shims.push(this.shim);
16155             delete this.shim;
16156         }
16157     },
16158
16159     disableShadow : function(){
16160         if(this.shadow){
16161             this.shadowDisabled = true;
16162             this.shadow.hide();
16163             this.lastShadowOffset = this.shadowOffset;
16164             this.shadowOffset = 0;
16165         }
16166     },
16167
16168     enableShadow : function(show){
16169         if(this.shadow){
16170             this.shadowDisabled = false;
16171             this.shadowOffset = this.lastShadowOffset;
16172             delete this.lastShadowOffset;
16173             if(show){
16174                 this.sync(true);
16175             }
16176         }
16177     },
16178
16179     // private
16180     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16181     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16182     sync : function(doShow){
16183         var sw = this.shadow;
16184         if(!this.updating && this.isVisible() && (sw || this.useShim)){
16185             var sh = this.getShim();
16186
16187             var w = this.getWidth(),
16188                 h = this.getHeight();
16189
16190             var l = this.getLeft(true),
16191                 t = this.getTop(true);
16192
16193             if(sw && !this.shadowDisabled){
16194                 if(doShow && !sw.isVisible()){
16195                     sw.show(this);
16196                 }else{
16197                     sw.realign(l, t, w, h);
16198                 }
16199                 if(sh){
16200                     if(doShow){
16201                        sh.show();
16202                     }
16203                     // fit the shim behind the shadow, so it is shimmed too
16204                     var a = sw.adjusts, s = sh.dom.style;
16205                     s.left = (Math.min(l, l+a.l))+"px";
16206                     s.top = (Math.min(t, t+a.t))+"px";
16207                     s.width = (w+a.w)+"px";
16208                     s.height = (h+a.h)+"px";
16209                 }
16210             }else if(sh){
16211                 if(doShow){
16212                    sh.show();
16213                 }
16214                 sh.setSize(w, h);
16215                 sh.setLeftTop(l, t);
16216             }
16217             
16218         }
16219     },
16220
16221     // private
16222     destroy : function(){
16223         this.hideShim();
16224         if(this.shadow){
16225             this.shadow.hide();
16226         }
16227         this.removeAllListeners();
16228         var pn = this.dom.parentNode;
16229         if(pn){
16230             pn.removeChild(this.dom);
16231         }
16232         Roo.Element.uncache(this.id);
16233     },
16234
16235     remove : function(){
16236         this.destroy();
16237     },
16238
16239     // private
16240     beginUpdate : function(){
16241         this.updating = true;
16242     },
16243
16244     // private
16245     endUpdate : function(){
16246         this.updating = false;
16247         this.sync(true);
16248     },
16249
16250     // private
16251     hideUnders : function(negOffset){
16252         if(this.shadow){
16253             this.shadow.hide();
16254         }
16255         this.hideShim();
16256     },
16257
16258     // private
16259     constrainXY : function(){
16260         if(this.constrain){
16261             var vw = Roo.lib.Dom.getViewWidth(),
16262                 vh = Roo.lib.Dom.getViewHeight();
16263             var s = Roo.get(document).getScroll();
16264
16265             var xy = this.getXY();
16266             var x = xy[0], y = xy[1];   
16267             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16268             // only move it if it needs it
16269             var moved = false;
16270             // first validate right/bottom
16271             if((x + w) > vw+s.left){
16272                 x = vw - w - this.shadowOffset;
16273                 moved = true;
16274             }
16275             if((y + h) > vh+s.top){
16276                 y = vh - h - this.shadowOffset;
16277                 moved = true;
16278             }
16279             // then make sure top/left isn't negative
16280             if(x < s.left){
16281                 x = s.left;
16282                 moved = true;
16283             }
16284             if(y < s.top){
16285                 y = s.top;
16286                 moved = true;
16287             }
16288             if(moved){
16289                 if(this.avoidY){
16290                     var ay = this.avoidY;
16291                     if(y <= ay && (y+h) >= ay){
16292                         y = ay-h-5;   
16293                     }
16294                 }
16295                 xy = [x, y];
16296                 this.storeXY(xy);
16297                 supr.setXY.call(this, xy);
16298                 this.sync();
16299             }
16300         }
16301     },
16302
16303     isVisible : function(){
16304         return this.visible;    
16305     },
16306
16307     // private
16308     showAction : function(){
16309         this.visible = true; // track visibility to prevent getStyle calls
16310         if(this.useDisplay === true){
16311             this.setDisplayed("");
16312         }else if(this.lastXY){
16313             supr.setXY.call(this, this.lastXY);
16314         }else if(this.lastLT){
16315             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16316         }
16317     },
16318
16319     // private
16320     hideAction : function(){
16321         this.visible = false;
16322         if(this.useDisplay === true){
16323             this.setDisplayed(false);
16324         }else{
16325             this.setLeftTop(-10000,-10000);
16326         }
16327     },
16328
16329     // overridden Element method
16330     setVisible : function(v, a, d, c, e){
16331         if(v){
16332             this.showAction();
16333         }
16334         if(a && v){
16335             var cb = function(){
16336                 this.sync(true);
16337                 if(c){
16338                     c();
16339                 }
16340             }.createDelegate(this);
16341             supr.setVisible.call(this, true, true, d, cb, e);
16342         }else{
16343             if(!v){
16344                 this.hideUnders(true);
16345             }
16346             var cb = c;
16347             if(a){
16348                 cb = function(){
16349                     this.hideAction();
16350                     if(c){
16351                         c();
16352                     }
16353                 }.createDelegate(this);
16354             }
16355             supr.setVisible.call(this, v, a, d, cb, e);
16356             if(v){
16357                 this.sync(true);
16358             }else if(!a){
16359                 this.hideAction();
16360             }
16361         }
16362     },
16363
16364     storeXY : function(xy){
16365         delete this.lastLT;
16366         this.lastXY = xy;
16367     },
16368
16369     storeLeftTop : function(left, top){
16370         delete this.lastXY;
16371         this.lastLT = [left, top];
16372     },
16373
16374     // private
16375     beforeFx : function(){
16376         this.beforeAction();
16377         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16378     },
16379
16380     // private
16381     afterFx : function(){
16382         Roo.Layer.superclass.afterFx.apply(this, arguments);
16383         this.sync(this.isVisible());
16384     },
16385
16386     // private
16387     beforeAction : function(){
16388         if(!this.updating && this.shadow){
16389             this.shadow.hide();
16390         }
16391     },
16392
16393     // overridden Element method
16394     setLeft : function(left){
16395         this.storeLeftTop(left, this.getTop(true));
16396         supr.setLeft.apply(this, arguments);
16397         this.sync();
16398     },
16399
16400     setTop : function(top){
16401         this.storeLeftTop(this.getLeft(true), top);
16402         supr.setTop.apply(this, arguments);
16403         this.sync();
16404     },
16405
16406     setLeftTop : function(left, top){
16407         this.storeLeftTop(left, top);
16408         supr.setLeftTop.apply(this, arguments);
16409         this.sync();
16410     },
16411
16412     setXY : function(xy, a, d, c, e){
16413         this.fixDisplay();
16414         this.beforeAction();
16415         this.storeXY(xy);
16416         var cb = this.createCB(c);
16417         supr.setXY.call(this, xy, a, d, cb, e);
16418         if(!a){
16419             cb();
16420         }
16421     },
16422
16423     // private
16424     createCB : function(c){
16425         var el = this;
16426         return function(){
16427             el.constrainXY();
16428             el.sync(true);
16429             if(c){
16430                 c();
16431             }
16432         };
16433     },
16434
16435     // overridden Element method
16436     setX : function(x, a, d, c, e){
16437         this.setXY([x, this.getY()], a, d, c, e);
16438     },
16439
16440     // overridden Element method
16441     setY : function(y, a, d, c, e){
16442         this.setXY([this.getX(), y], a, d, c, e);
16443     },
16444
16445     // overridden Element method
16446     setSize : function(w, h, a, d, c, e){
16447         this.beforeAction();
16448         var cb = this.createCB(c);
16449         supr.setSize.call(this, w, h, a, d, cb, e);
16450         if(!a){
16451             cb();
16452         }
16453     },
16454
16455     // overridden Element method
16456     setWidth : function(w, a, d, c, e){
16457         this.beforeAction();
16458         var cb = this.createCB(c);
16459         supr.setWidth.call(this, w, a, d, cb, e);
16460         if(!a){
16461             cb();
16462         }
16463     },
16464
16465     // overridden Element method
16466     setHeight : function(h, a, d, c, e){
16467         this.beforeAction();
16468         var cb = this.createCB(c);
16469         supr.setHeight.call(this, h, a, d, cb, e);
16470         if(!a){
16471             cb();
16472         }
16473     },
16474
16475     // overridden Element method
16476     setBounds : function(x, y, w, h, a, d, c, e){
16477         this.beforeAction();
16478         var cb = this.createCB(c);
16479         if(!a){
16480             this.storeXY([x, y]);
16481             supr.setXY.call(this, [x, y]);
16482             supr.setSize.call(this, w, h, a, d, cb, e);
16483             cb();
16484         }else{
16485             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16486         }
16487         return this;
16488     },
16489     
16490     /**
16491      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16492      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16493      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16494      * @param {Number} zindex The new z-index to set
16495      * @return {this} The Layer
16496      */
16497     setZIndex : function(zindex){
16498         this.zindex = zindex;
16499         this.setStyle("z-index", zindex + 2);
16500         if(this.shadow){
16501             this.shadow.setZIndex(zindex + 1);
16502         }
16503         if(this.shim){
16504             this.shim.setStyle("z-index", zindex);
16505         }
16506     }
16507 });
16508 })();/*
16509  * Original code for Roojs - LGPL
16510  * <script type="text/javascript">
16511  */
16512  
16513 /**
16514  * @class Roo.XComponent
16515  * A delayed Element creator...
16516  * Or a way to group chunks of interface together.
16517  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16518  *  used in conjunction with XComponent.build() it will create an instance of each element,
16519  *  then call addxtype() to build the User interface.
16520  * 
16521  * Mypart.xyx = new Roo.XComponent({
16522
16523     parent : 'Mypart.xyz', // empty == document.element.!!
16524     order : '001',
16525     name : 'xxxx'
16526     region : 'xxxx'
16527     disabled : function() {} 
16528      
16529     tree : function() { // return an tree of xtype declared components
16530         var MODULE = this;
16531         return 
16532         {
16533             xtype : 'NestedLayoutPanel',
16534             // technicall
16535         }
16536      ]
16537  *})
16538  *
16539  *
16540  * It can be used to build a big heiracy, with parent etc.
16541  * or you can just use this to render a single compoent to a dom element
16542  * MYPART.render(Roo.Element | String(id) | dom_element )
16543  *
16544  *
16545  * Usage patterns.
16546  *
16547  * Classic Roo
16548  *
16549  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16550  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16551  *
16552  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16553  *
16554  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16555  * - if mulitple topModules exist, the last one is defined as the top module.
16556  *
16557  * Embeded Roo
16558  * 
16559  * When the top level or multiple modules are to embedded into a existing HTML page,
16560  * the parent element can container '#id' of the element where the module will be drawn.
16561  *
16562  * Bootstrap Roo
16563  *
16564  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16565  * it relies more on a include mechanism, where sub modules are included into an outer page.
16566  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16567  * 
16568  * Bootstrap Roo Included elements
16569  *
16570  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16571  * hence confusing the component builder as it thinks there are multiple top level elements. 
16572  *
16573  * String Over-ride & Translations
16574  *
16575  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16576  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16577  * are needed. @see Roo.XComponent.overlayString  
16578  * 
16579  * 
16580  * 
16581  * @extends Roo.util.Observable
16582  * @constructor
16583  * @param cfg {Object} configuration of component
16584  * 
16585  */
16586 Roo.XComponent = function(cfg) {
16587     Roo.apply(this, cfg);
16588     this.addEvents({ 
16589         /**
16590              * @event built
16591              * Fires when this the componnt is built
16592              * @param {Roo.XComponent} c the component
16593              */
16594         'built' : true
16595         
16596     });
16597     this.region = this.region || 'center'; // default..
16598     Roo.XComponent.register(this);
16599     this.modules = false;
16600     this.el = false; // where the layout goes..
16601     
16602     
16603 }
16604 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16605     /**
16606      * @property el
16607      * The created element (with Roo.factory())
16608      * @type {Roo.Layout}
16609      */
16610     el  : false,
16611     
16612     /**
16613      * @property el
16614      * for BC  - use el in new code
16615      * @type {Roo.Layout}
16616      */
16617     panel : false,
16618     
16619     /**
16620      * @property layout
16621      * for BC  - use el in new code
16622      * @type {Roo.Layout}
16623      */
16624     layout : false,
16625     
16626      /**
16627      * @cfg {Function|boolean} disabled
16628      * If this module is disabled by some rule, return true from the funtion
16629      */
16630     disabled : false,
16631     
16632     /**
16633      * @cfg {String} parent 
16634      * Name of parent element which it get xtype added to..
16635      */
16636     parent: false,
16637     
16638     /**
16639      * @cfg {String} order
16640      * Used to set the order in which elements are created (usefull for multiple tabs)
16641      */
16642     
16643     order : false,
16644     /**
16645      * @cfg {String} name
16646      * String to display while loading.
16647      */
16648     name : false,
16649     /**
16650      * @cfg {String} region
16651      * Region to render component to (defaults to center)
16652      */
16653     region : 'center',
16654     
16655     /**
16656      * @cfg {Array} items
16657      * A single item array - the first element is the root of the tree..
16658      * It's done this way to stay compatible with the Xtype system...
16659      */
16660     items : false,
16661     
16662     /**
16663      * @property _tree
16664      * The method that retuns the tree of parts that make up this compoennt 
16665      * @type {function}
16666      */
16667     _tree  : false,
16668     
16669      /**
16670      * render
16671      * render element to dom or tree
16672      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16673      */
16674     
16675     render : function(el)
16676     {
16677         
16678         el = el || false;
16679         var hp = this.parent ? 1 : 0;
16680         Roo.debug &&  Roo.log(this);
16681         
16682         var tree = this._tree ? this._tree() : this.tree();
16683
16684         
16685         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16686             // if parent is a '#.....' string, then let's use that..
16687             var ename = this.parent.substr(1);
16688             this.parent = false;
16689             Roo.debug && Roo.log(ename);
16690             switch (ename) {
16691                 case 'bootstrap-body':
16692                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16693                         // this is the BorderLayout standard?
16694                        this.parent = { el : true };
16695                        break;
16696                     }
16697                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16698                         // need to insert stuff...
16699                         this.parent =  {
16700                              el : new Roo.bootstrap.layout.Border({
16701                                  el : document.body, 
16702                      
16703                                  center: {
16704                                     titlebar: false,
16705                                     autoScroll:false,
16706                                     closeOnTab: true,
16707                                     tabPosition: 'top',
16708                                       //resizeTabs: true,
16709                                     alwaysShowTabs: true,
16710                                     hideTabs: false
16711                                      //minTabWidth: 140
16712                                  }
16713                              })
16714                         
16715                          };
16716                          break;
16717                     }
16718                          
16719                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16720                         this.parent = { el :  new  Roo.bootstrap.Body() };
16721                         Roo.debug && Roo.log("setting el to doc body");
16722                          
16723                     } else {
16724                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16725                     }
16726                     break;
16727                 case 'bootstrap':
16728                     this.parent = { el : true};
16729                     // fall through
16730                 default:
16731                     el = Roo.get(ename);
16732                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16733                         this.parent = { el : true};
16734                     }
16735                     
16736                     break;
16737             }
16738                 
16739             
16740             if (!el && !this.parent) {
16741                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16742                 return;
16743             }
16744         }
16745         
16746         Roo.debug && Roo.log("EL:");
16747         Roo.debug && Roo.log(el);
16748         Roo.debug && Roo.log("this.parent.el:");
16749         Roo.debug && Roo.log(this.parent.el);
16750         
16751
16752         // altertive root elements ??? - we need a better way to indicate these.
16753         var is_alt = Roo.XComponent.is_alt ||
16754                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16755                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16756                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16757         
16758         
16759         
16760         if (!this.parent && is_alt) {
16761             //el = Roo.get(document.body);
16762             this.parent = { el : true };
16763         }
16764             
16765             
16766         
16767         if (!this.parent) {
16768             
16769             Roo.debug && Roo.log("no parent - creating one");
16770             
16771             el = el ? Roo.get(el) : false;      
16772             
16773             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16774                 
16775                 this.parent =  {
16776                     el : new Roo.bootstrap.layout.Border({
16777                         el: el || document.body,
16778                     
16779                         center: {
16780                             titlebar: false,
16781                             autoScroll:false,
16782                             closeOnTab: true,
16783                             tabPosition: 'top',
16784                              //resizeTabs: true,
16785                             alwaysShowTabs: false,
16786                             hideTabs: true,
16787                             minTabWidth: 140,
16788                             overflow: 'visible'
16789                          }
16790                      })
16791                 };
16792             } else {
16793             
16794                 // it's a top level one..
16795                 this.parent =  {
16796                     el : new Roo.BorderLayout(el || document.body, {
16797                         center: {
16798                             titlebar: false,
16799                             autoScroll:false,
16800                             closeOnTab: true,
16801                             tabPosition: 'top',
16802                              //resizeTabs: true,
16803                             alwaysShowTabs: el && hp? false :  true,
16804                             hideTabs: el || !hp ? true :  false,
16805                             minTabWidth: 140
16806                          }
16807                     })
16808                 };
16809             }
16810         }
16811         
16812         if (!this.parent.el) {
16813                 // probably an old style ctor, which has been disabled.
16814                 return;
16815
16816         }
16817                 // The 'tree' method is  '_tree now' 
16818             
16819         tree.region = tree.region || this.region;
16820         var is_body = false;
16821         if (this.parent.el === true) {
16822             // bootstrap... - body..
16823             if (el) {
16824                 tree.el = el;
16825             }
16826             this.parent.el = Roo.factory(tree);
16827             is_body = true;
16828         }
16829         
16830         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16831         this.fireEvent('built', this);
16832         
16833         this.panel = this.el;
16834         this.layout = this.panel.layout;
16835         this.parentLayout = this.parent.layout  || false;  
16836          
16837     }
16838     
16839 });
16840
16841 Roo.apply(Roo.XComponent, {
16842     /**
16843      * @property  hideProgress
16844      * true to disable the building progress bar.. usefull on single page renders.
16845      * @type Boolean
16846      */
16847     hideProgress : false,
16848     /**
16849      * @property  buildCompleted
16850      * True when the builder has completed building the interface.
16851      * @type Boolean
16852      */
16853     buildCompleted : false,
16854      
16855     /**
16856      * @property  topModule
16857      * the upper most module - uses document.element as it's constructor.
16858      * @type Object
16859      */
16860      
16861     topModule  : false,
16862       
16863     /**
16864      * @property  modules
16865      * array of modules to be created by registration system.
16866      * @type {Array} of Roo.XComponent
16867      */
16868     
16869     modules : [],
16870     /**
16871      * @property  elmodules
16872      * array of modules to be created by which use #ID 
16873      * @type {Array} of Roo.XComponent
16874      */
16875      
16876     elmodules : [],
16877
16878      /**
16879      * @property  is_alt
16880      * Is an alternative Root - normally used by bootstrap or other systems,
16881      *    where the top element in the tree can wrap 'body' 
16882      * @type {boolean}  (default false)
16883      */
16884      
16885     is_alt : false,
16886     /**
16887      * @property  build_from_html
16888      * Build elements from html - used by bootstrap HTML stuff 
16889      *    - this is cleared after build is completed
16890      * @type {boolean}    (default false)
16891      */
16892      
16893     build_from_html : false,
16894     /**
16895      * Register components to be built later.
16896      *
16897      * This solves the following issues
16898      * - Building is not done on page load, but after an authentication process has occured.
16899      * - Interface elements are registered on page load
16900      * - Parent Interface elements may not be loaded before child, so this handles that..
16901      * 
16902      *
16903      * example:
16904      * 
16905      * MyApp.register({
16906           order : '000001',
16907           module : 'Pman.Tab.projectMgr',
16908           region : 'center',
16909           parent : 'Pman.layout',
16910           disabled : false,  // or use a function..
16911         })
16912      
16913      * * @param {Object} details about module
16914      */
16915     register : function(obj) {
16916                 
16917         Roo.XComponent.event.fireEvent('register', obj);
16918         switch(typeof(obj.disabled) ) {
16919                 
16920             case 'undefined':
16921                 break;
16922             
16923             case 'function':
16924                 if ( obj.disabled() ) {
16925                         return;
16926                 }
16927                 break;
16928             
16929             default:
16930                 if (obj.disabled || obj.region == '#disabled') {
16931                         return;
16932                 }
16933                 break;
16934         }
16935                 
16936         this.modules.push(obj);
16937          
16938     },
16939     /**
16940      * convert a string to an object..
16941      * eg. 'AAA.BBB' -> finds AAA.BBB
16942
16943      */
16944     
16945     toObject : function(str)
16946     {
16947         if (!str || typeof(str) == 'object') {
16948             return str;
16949         }
16950         if (str.substring(0,1) == '#') {
16951             return str;
16952         }
16953
16954         var ar = str.split('.');
16955         var rt, o;
16956         rt = ar.shift();
16957             /** eval:var:o */
16958         try {
16959             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16960         } catch (e) {
16961             throw "Module not found : " + str;
16962         }
16963         
16964         if (o === false) {
16965             throw "Module not found : " + str;
16966         }
16967         Roo.each(ar, function(e) {
16968             if (typeof(o[e]) == 'undefined') {
16969                 throw "Module not found : " + str;
16970             }
16971             o = o[e];
16972         });
16973         
16974         return o;
16975         
16976     },
16977     
16978     
16979     /**
16980      * move modules into their correct place in the tree..
16981      * 
16982      */
16983     preBuild : function ()
16984     {
16985         var _t = this;
16986         Roo.each(this.modules , function (obj)
16987         {
16988             Roo.XComponent.event.fireEvent('beforebuild', obj);
16989             
16990             var opar = obj.parent;
16991             try { 
16992                 obj.parent = this.toObject(opar);
16993             } catch(e) {
16994                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16995                 return;
16996             }
16997             
16998             if (!obj.parent) {
16999                 Roo.debug && Roo.log("GOT top level module");
17000                 Roo.debug && Roo.log(obj);
17001                 obj.modules = new Roo.util.MixedCollection(false, 
17002                     function(o) { return o.order + '' }
17003                 );
17004                 this.topModule = obj;
17005                 return;
17006             }
17007                         // parent is a string (usually a dom element name..)
17008             if (typeof(obj.parent) == 'string') {
17009                 this.elmodules.push(obj);
17010                 return;
17011             }
17012             if (obj.parent.constructor != Roo.XComponent) {
17013                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17014             }
17015             if (!obj.parent.modules) {
17016                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17017                     function(o) { return o.order + '' }
17018                 );
17019             }
17020             if (obj.parent.disabled) {
17021                 obj.disabled = true;
17022             }
17023             obj.parent.modules.add(obj);
17024         }, this);
17025     },
17026     
17027      /**
17028      * make a list of modules to build.
17029      * @return {Array} list of modules. 
17030      */ 
17031     
17032     buildOrder : function()
17033     {
17034         var _this = this;
17035         var cmp = function(a,b) {   
17036             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17037         };
17038         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17039             throw "No top level modules to build";
17040         }
17041         
17042         // make a flat list in order of modules to build.
17043         var mods = this.topModule ? [ this.topModule ] : [];
17044                 
17045         
17046         // elmodules (is a list of DOM based modules )
17047         Roo.each(this.elmodules, function(e) {
17048             mods.push(e);
17049             if (!this.topModule &&
17050                 typeof(e.parent) == 'string' &&
17051                 e.parent.substring(0,1) == '#' &&
17052                 Roo.get(e.parent.substr(1))
17053                ) {
17054                 
17055                 _this.topModule = e;
17056             }
17057             
17058         });
17059
17060         
17061         // add modules to their parents..
17062         var addMod = function(m) {
17063             Roo.debug && Roo.log("build Order: add: " + m.name);
17064                 
17065             mods.push(m);
17066             if (m.modules && !m.disabled) {
17067                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17068                 m.modules.keySort('ASC',  cmp );
17069                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17070     
17071                 m.modules.each(addMod);
17072             } else {
17073                 Roo.debug && Roo.log("build Order: no child modules");
17074             }
17075             // not sure if this is used any more..
17076             if (m.finalize) {
17077                 m.finalize.name = m.name + " (clean up) ";
17078                 mods.push(m.finalize);
17079             }
17080             
17081         }
17082         if (this.topModule && this.topModule.modules) { 
17083             this.topModule.modules.keySort('ASC',  cmp );
17084             this.topModule.modules.each(addMod);
17085         } 
17086         return mods;
17087     },
17088     
17089      /**
17090      * Build the registered modules.
17091      * @param {Object} parent element.
17092      * @param {Function} optional method to call after module has been added.
17093      * 
17094      */ 
17095    
17096     build : function(opts) 
17097     {
17098         
17099         if (typeof(opts) != 'undefined') {
17100             Roo.apply(this,opts);
17101         }
17102         
17103         this.preBuild();
17104         var mods = this.buildOrder();
17105       
17106         //this.allmods = mods;
17107         //Roo.debug && Roo.log(mods);
17108         //return;
17109         if (!mods.length) { // should not happen
17110             throw "NO modules!!!";
17111         }
17112         
17113         
17114         var msg = "Building Interface...";
17115         // flash it up as modal - so we store the mask!?
17116         if (!this.hideProgress && Roo.MessageBox) {
17117             Roo.MessageBox.show({ title: 'loading' });
17118             Roo.MessageBox.show({
17119                title: "Please wait...",
17120                msg: msg,
17121                width:450,
17122                progress:true,
17123                buttons : false,
17124                closable:false,
17125                modal: false
17126               
17127             });
17128         }
17129         var total = mods.length;
17130         
17131         var _this = this;
17132         var progressRun = function() {
17133             if (!mods.length) {
17134                 Roo.debug && Roo.log('hide?');
17135                 if (!this.hideProgress && Roo.MessageBox) {
17136                     Roo.MessageBox.hide();
17137                 }
17138                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17139                 
17140                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17141                 
17142                 // THE END...
17143                 return false;   
17144             }
17145             
17146             var m = mods.shift();
17147             
17148             
17149             Roo.debug && Roo.log(m);
17150             // not sure if this is supported any more.. - modules that are are just function
17151             if (typeof(m) == 'function') { 
17152                 m.call(this);
17153                 return progressRun.defer(10, _this);
17154             } 
17155             
17156             
17157             msg = "Building Interface " + (total  - mods.length) + 
17158                     " of " + total + 
17159                     (m.name ? (' - ' + m.name) : '');
17160                         Roo.debug && Roo.log(msg);
17161             if (!_this.hideProgress &&  Roo.MessageBox) { 
17162                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
17163             }
17164             
17165          
17166             // is the module disabled?
17167             var disabled = (typeof(m.disabled) == 'function') ?
17168                 m.disabled.call(m.module.disabled) : m.disabled;    
17169             
17170             
17171             if (disabled) {
17172                 return progressRun(); // we do not update the display!
17173             }
17174             
17175             // now build 
17176             
17177                         
17178                         
17179             m.render();
17180             // it's 10 on top level, and 1 on others??? why...
17181             return progressRun.defer(10, _this);
17182              
17183         }
17184         progressRun.defer(1, _this);
17185      
17186         
17187         
17188     },
17189     /**
17190      * Overlay a set of modified strings onto a component
17191      * This is dependant on our builder exporting the strings and 'named strings' elements.
17192      * 
17193      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17194      * @param {Object} associative array of 'named' string and it's new value.
17195      * 
17196      */
17197         overlayStrings : function( component, strings )
17198     {
17199         if (typeof(component['_named_strings']) == 'undefined') {
17200             throw "ERROR: component does not have _named_strings";
17201         }
17202         for ( var k in strings ) {
17203             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17204             if (md !== false) {
17205                 component['_strings'][md] = strings[k];
17206             } else {
17207                 Roo.log('could not find named string: ' + k + ' in');
17208                 Roo.log(component);
17209             }
17210             
17211         }
17212         
17213     },
17214     
17215         
17216         /**
17217          * Event Object.
17218          *
17219          *
17220          */
17221         event: false, 
17222     /**
17223          * wrapper for event.on - aliased later..  
17224          * Typically use to register a event handler for register:
17225          *
17226          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17227          *
17228          */
17229     on : false
17230    
17231     
17232     
17233 });
17234
17235 Roo.XComponent.event = new Roo.util.Observable({
17236                 events : { 
17237                         /**
17238                          * @event register
17239                          * Fires when an Component is registered,
17240                          * set the disable property on the Component to stop registration.
17241                          * @param {Roo.XComponent} c the component being registerd.
17242                          * 
17243                          */
17244                         'register' : true,
17245             /**
17246                          * @event beforebuild
17247                          * Fires before each Component is built
17248                          * can be used to apply permissions.
17249                          * @param {Roo.XComponent} c the component being registerd.
17250                          * 
17251                          */
17252                         'beforebuild' : true,
17253                         /**
17254                          * @event buildcomplete
17255                          * Fires on the top level element when all elements have been built
17256                          * @param {Roo.XComponent} the top level component.
17257                          */
17258                         'buildcomplete' : true
17259                         
17260                 }
17261 });
17262
17263 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
17264  //
17265  /**
17266  * marked - a markdown parser
17267  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17268  * https://github.com/chjj/marked
17269  */
17270
17271
17272 /**
17273  *
17274  * Roo.Markdown - is a very crude wrapper around marked..
17275  *
17276  * usage:
17277  * 
17278  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17279  * 
17280  * Note: move the sample code to the bottom of this
17281  * file before uncommenting it.
17282  *
17283  */
17284
17285 Roo.Markdown = {};
17286 Roo.Markdown.toHtml = function(text) {
17287     
17288     var c = new Roo.Markdown.marked.setOptions({
17289             renderer: new Roo.Markdown.marked.Renderer(),
17290             gfm: true,
17291             tables: true,
17292             breaks: false,
17293             pedantic: false,
17294             sanitize: false,
17295             smartLists: true,
17296             smartypants: false
17297           });
17298     // A FEW HACKS!!?
17299     
17300     text = text.replace(/\\\n/g,' ');
17301     return Roo.Markdown.marked(text);
17302 };
17303 //
17304 // converter
17305 //
17306 // Wraps all "globals" so that the only thing
17307 // exposed is makeHtml().
17308 //
17309 (function() {
17310     
17311      /**
17312          * eval:var:escape
17313          * eval:var:unescape
17314          * eval:var:replace
17315          */
17316       
17317     /**
17318      * Helpers
17319      */
17320     
17321     var escape = function (html, encode) {
17322       return html
17323         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17324         .replace(/</g, '&lt;')
17325         .replace(/>/g, '&gt;')
17326         .replace(/"/g, '&quot;')
17327         .replace(/'/g, '&#39;');
17328     }
17329     
17330     var unescape = function (html) {
17331         // explicitly match decimal, hex, and named HTML entities 
17332       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17333         n = n.toLowerCase();
17334         if (n === 'colon') { return ':'; }
17335         if (n.charAt(0) === '#') {
17336           return n.charAt(1) === 'x'
17337             ? String.fromCharCode(parseInt(n.substring(2), 16))
17338             : String.fromCharCode(+n.substring(1));
17339         }
17340         return '';
17341       });
17342     }
17343     
17344     var replace = function (regex, opt) {
17345       regex = regex.source;
17346       opt = opt || '';
17347       return function self(name, val) {
17348         if (!name) { return new RegExp(regex, opt); }
17349         val = val.source || val;
17350         val = val.replace(/(^|[^\[])\^/g, '$1');
17351         regex = regex.replace(name, val);
17352         return self;
17353       };
17354     }
17355
17356
17357          /**
17358          * eval:var:noop
17359     */
17360     var noop = function () {}
17361     noop.exec = noop;
17362     
17363          /**
17364          * eval:var:merge
17365     */
17366     var merge = function (obj) {
17367       var i = 1
17368         , target
17369         , key;
17370     
17371       for (; i < arguments.length; i++) {
17372         target = arguments[i];
17373         for (key in target) {
17374           if (Object.prototype.hasOwnProperty.call(target, key)) {
17375             obj[key] = target[key];
17376           }
17377         }
17378       }
17379     
17380       return obj;
17381     }
17382     
17383     
17384     /**
17385      * Block-Level Grammar
17386      */
17387     
17388     
17389     
17390     
17391     var block = {
17392       newline: /^\n+/,
17393       code: /^( {4}[^\n]+\n*)+/,
17394       fences: noop,
17395       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17396       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17397       nptable: noop,
17398       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17399       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17400       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17401       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17402       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17403       table: noop,
17404       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17405       text: /^[^\n]+/
17406     };
17407     
17408     block.bullet = /(?:[*+-]|\d+\.)/;
17409     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17410     block.item = replace(block.item, 'gm')
17411       (/bull/g, block.bullet)
17412       ();
17413     
17414     block.list = replace(block.list)
17415       (/bull/g, block.bullet)
17416       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17417       ('def', '\\n+(?=' + block.def.source + ')')
17418       ();
17419     
17420     block.blockquote = replace(block.blockquote)
17421       ('def', block.def)
17422       ();
17423     
17424     block._tag = '(?!(?:'
17425       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17426       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17427       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17428     
17429     block.html = replace(block.html)
17430       ('comment', /<!--[\s\S]*?-->/)
17431       ('closed', /<(tag)[\s\S]+?<\/\1>/)
17432       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17433       (/tag/g, block._tag)
17434       ();
17435     
17436     block.paragraph = replace(block.paragraph)
17437       ('hr', block.hr)
17438       ('heading', block.heading)
17439       ('lheading', block.lheading)
17440       ('blockquote', block.blockquote)
17441       ('tag', '<' + block._tag)
17442       ('def', block.def)
17443       ();
17444     
17445     /**
17446      * Normal Block Grammar
17447      */
17448     
17449     block.normal = merge({}, block);
17450     
17451     /**
17452      * GFM Block Grammar
17453      */
17454     
17455     block.gfm = merge({}, block.normal, {
17456       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17457       paragraph: /^/,
17458       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17459     });
17460     
17461     block.gfm.paragraph = replace(block.paragraph)
17462       ('(?!', '(?!'
17463         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17464         + block.list.source.replace('\\1', '\\3') + '|')
17465       ();
17466     
17467     /**
17468      * GFM + Tables Block Grammar
17469      */
17470     
17471     block.tables = merge({}, block.gfm, {
17472       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17473       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17474     });
17475     
17476     /**
17477      * Block Lexer
17478      */
17479     
17480     var Lexer = function (options) {
17481       this.tokens = [];
17482       this.tokens.links = {};
17483       this.options = options || marked.defaults;
17484       this.rules = block.normal;
17485     
17486       if (this.options.gfm) {
17487         if (this.options.tables) {
17488           this.rules = block.tables;
17489         } else {
17490           this.rules = block.gfm;
17491         }
17492       }
17493     }
17494     
17495     /**
17496      * Expose Block Rules
17497      */
17498     
17499     Lexer.rules = block;
17500     
17501     /**
17502      * Static Lex Method
17503      */
17504     
17505     Lexer.lex = function(src, options) {
17506       var lexer = new Lexer(options);
17507       return lexer.lex(src);
17508     };
17509     
17510     /**
17511      * Preprocessing
17512      */
17513     
17514     Lexer.prototype.lex = function(src) {
17515       src = src
17516         .replace(/\r\n|\r/g, '\n')
17517         .replace(/\t/g, '    ')
17518         .replace(/\u00a0/g, ' ')
17519         .replace(/\u2424/g, '\n');
17520     
17521       return this.token(src, true);
17522     };
17523     
17524     /**
17525      * Lexing
17526      */
17527     
17528     Lexer.prototype.token = function(src, top, bq) {
17529       var src = src.replace(/^ +$/gm, '')
17530         , next
17531         , loose
17532         , cap
17533         , bull
17534         , b
17535         , item
17536         , space
17537         , i
17538         , l;
17539     
17540       while (src) {
17541         // newline
17542         if (cap = this.rules.newline.exec(src)) {
17543           src = src.substring(cap[0].length);
17544           if (cap[0].length > 1) {
17545             this.tokens.push({
17546               type: 'space'
17547             });
17548           }
17549         }
17550     
17551         // code
17552         if (cap = this.rules.code.exec(src)) {
17553           src = src.substring(cap[0].length);
17554           cap = cap[0].replace(/^ {4}/gm, '');
17555           this.tokens.push({
17556             type: 'code',
17557             text: !this.options.pedantic
17558               ? cap.replace(/\n+$/, '')
17559               : cap
17560           });
17561           continue;
17562         }
17563     
17564         // fences (gfm)
17565         if (cap = this.rules.fences.exec(src)) {
17566           src = src.substring(cap[0].length);
17567           this.tokens.push({
17568             type: 'code',
17569             lang: cap[2],
17570             text: cap[3] || ''
17571           });
17572           continue;
17573         }
17574     
17575         // heading
17576         if (cap = this.rules.heading.exec(src)) {
17577           src = src.substring(cap[0].length);
17578           this.tokens.push({
17579             type: 'heading',
17580             depth: cap[1].length,
17581             text: cap[2]
17582           });
17583           continue;
17584         }
17585     
17586         // table no leading pipe (gfm)
17587         if (top && (cap = this.rules.nptable.exec(src))) {
17588           src = src.substring(cap[0].length);
17589     
17590           item = {
17591             type: 'table',
17592             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17593             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17594             cells: cap[3].replace(/\n$/, '').split('\n')
17595           };
17596     
17597           for (i = 0; i < item.align.length; i++) {
17598             if (/^ *-+: *$/.test(item.align[i])) {
17599               item.align[i] = 'right';
17600             } else if (/^ *:-+: *$/.test(item.align[i])) {
17601               item.align[i] = 'center';
17602             } else if (/^ *:-+ *$/.test(item.align[i])) {
17603               item.align[i] = 'left';
17604             } else {
17605               item.align[i] = null;
17606             }
17607           }
17608     
17609           for (i = 0; i < item.cells.length; i++) {
17610             item.cells[i] = item.cells[i].split(/ *\| */);
17611           }
17612     
17613           this.tokens.push(item);
17614     
17615           continue;
17616         }
17617     
17618         // lheading
17619         if (cap = this.rules.lheading.exec(src)) {
17620           src = src.substring(cap[0].length);
17621           this.tokens.push({
17622             type: 'heading',
17623             depth: cap[2] === '=' ? 1 : 2,
17624             text: cap[1]
17625           });
17626           continue;
17627         }
17628     
17629         // hr
17630         if (cap = this.rules.hr.exec(src)) {
17631           src = src.substring(cap[0].length);
17632           this.tokens.push({
17633             type: 'hr'
17634           });
17635           continue;
17636         }
17637     
17638         // blockquote
17639         if (cap = this.rules.blockquote.exec(src)) {
17640           src = src.substring(cap[0].length);
17641     
17642           this.tokens.push({
17643             type: 'blockquote_start'
17644           });
17645     
17646           cap = cap[0].replace(/^ *> ?/gm, '');
17647     
17648           // Pass `top` to keep the current
17649           // "toplevel" state. This is exactly
17650           // how markdown.pl works.
17651           this.token(cap, top, true);
17652     
17653           this.tokens.push({
17654             type: 'blockquote_end'
17655           });
17656     
17657           continue;
17658         }
17659     
17660         // list
17661         if (cap = this.rules.list.exec(src)) {
17662           src = src.substring(cap[0].length);
17663           bull = cap[2];
17664     
17665           this.tokens.push({
17666             type: 'list_start',
17667             ordered: bull.length > 1
17668           });
17669     
17670           // Get each top-level item.
17671           cap = cap[0].match(this.rules.item);
17672     
17673           next = false;
17674           l = cap.length;
17675           i = 0;
17676     
17677           for (; i < l; i++) {
17678             item = cap[i];
17679     
17680             // Remove the list item's bullet
17681             // so it is seen as the next token.
17682             space = item.length;
17683             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17684     
17685             // Outdent whatever the
17686             // list item contains. Hacky.
17687             if (~item.indexOf('\n ')) {
17688               space -= item.length;
17689               item = !this.options.pedantic
17690                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17691                 : item.replace(/^ {1,4}/gm, '');
17692             }
17693     
17694             // Determine whether the next list item belongs here.
17695             // Backpedal if it does not belong in this list.
17696             if (this.options.smartLists && i !== l - 1) {
17697               b = block.bullet.exec(cap[i + 1])[0];
17698               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17699                 src = cap.slice(i + 1).join('\n') + src;
17700                 i = l - 1;
17701               }
17702             }
17703     
17704             // Determine whether item is loose or not.
17705             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17706             // for discount behavior.
17707             loose = next || /\n\n(?!\s*$)/.test(item);
17708             if (i !== l - 1) {
17709               next = item.charAt(item.length - 1) === '\n';
17710               if (!loose) { loose = next; }
17711             }
17712     
17713             this.tokens.push({
17714               type: loose
17715                 ? 'loose_item_start'
17716                 : 'list_item_start'
17717             });
17718     
17719             // Recurse.
17720             this.token(item, false, bq);
17721     
17722             this.tokens.push({
17723               type: 'list_item_end'
17724             });
17725           }
17726     
17727           this.tokens.push({
17728             type: 'list_end'
17729           });
17730     
17731           continue;
17732         }
17733     
17734         // html
17735         if (cap = this.rules.html.exec(src)) {
17736           src = src.substring(cap[0].length);
17737           this.tokens.push({
17738             type: this.options.sanitize
17739               ? 'paragraph'
17740               : 'html',
17741             pre: !this.options.sanitizer
17742               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17743             text: cap[0]
17744           });
17745           continue;
17746         }
17747     
17748         // def
17749         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17750           src = src.substring(cap[0].length);
17751           this.tokens.links[cap[1].toLowerCase()] = {
17752             href: cap[2],
17753             title: cap[3]
17754           };
17755           continue;
17756         }
17757     
17758         // table (gfm)
17759         if (top && (cap = this.rules.table.exec(src))) {
17760           src = src.substring(cap[0].length);
17761     
17762           item = {
17763             type: 'table',
17764             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17765             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17766             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17767           };
17768     
17769           for (i = 0; i < item.align.length; i++) {
17770             if (/^ *-+: *$/.test(item.align[i])) {
17771               item.align[i] = 'right';
17772             } else if (/^ *:-+: *$/.test(item.align[i])) {
17773               item.align[i] = 'center';
17774             } else if (/^ *:-+ *$/.test(item.align[i])) {
17775               item.align[i] = 'left';
17776             } else {
17777               item.align[i] = null;
17778             }
17779           }
17780     
17781           for (i = 0; i < item.cells.length; i++) {
17782             item.cells[i] = item.cells[i]
17783               .replace(/^ *\| *| *\| *$/g, '')
17784               .split(/ *\| */);
17785           }
17786     
17787           this.tokens.push(item);
17788     
17789           continue;
17790         }
17791     
17792         // top-level paragraph
17793         if (top && (cap = this.rules.paragraph.exec(src))) {
17794           src = src.substring(cap[0].length);
17795           this.tokens.push({
17796             type: 'paragraph',
17797             text: cap[1].charAt(cap[1].length - 1) === '\n'
17798               ? cap[1].slice(0, -1)
17799               : cap[1]
17800           });
17801           continue;
17802         }
17803     
17804         // text
17805         if (cap = this.rules.text.exec(src)) {
17806           // Top-level should never reach here.
17807           src = src.substring(cap[0].length);
17808           this.tokens.push({
17809             type: 'text',
17810             text: cap[0]
17811           });
17812           continue;
17813         }
17814     
17815         if (src) {
17816           throw new
17817             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17818         }
17819       }
17820     
17821       return this.tokens;
17822     };
17823     
17824     /**
17825      * Inline-Level Grammar
17826      */
17827     
17828     var inline = {
17829       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17830       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17831       url: noop,
17832       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17833       link: /^!?\[(inside)\]\(href\)/,
17834       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17835       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17836       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17837       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17838       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17839       br: /^ {2,}\n(?!\s*$)/,
17840       del: noop,
17841       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17842     };
17843     
17844     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17845     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17846     
17847     inline.link = replace(inline.link)
17848       ('inside', inline._inside)
17849       ('href', inline._href)
17850       ();
17851     
17852     inline.reflink = replace(inline.reflink)
17853       ('inside', inline._inside)
17854       ();
17855     
17856     /**
17857      * Normal Inline Grammar
17858      */
17859     
17860     inline.normal = merge({}, inline);
17861     
17862     /**
17863      * Pedantic Inline Grammar
17864      */
17865     
17866     inline.pedantic = merge({}, inline.normal, {
17867       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17868       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17869     });
17870     
17871     /**
17872      * GFM Inline Grammar
17873      */
17874     
17875     inline.gfm = merge({}, inline.normal, {
17876       escape: replace(inline.escape)('])', '~|])')(),
17877       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17878       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17879       text: replace(inline.text)
17880         (']|', '~]|')
17881         ('|', '|https?://|')
17882         ()
17883     });
17884     
17885     /**
17886      * GFM + Line Breaks Inline Grammar
17887      */
17888     
17889     inline.breaks = merge({}, inline.gfm, {
17890       br: replace(inline.br)('{2,}', '*')(),
17891       text: replace(inline.gfm.text)('{2,}', '*')()
17892     });
17893     
17894     /**
17895      * Inline Lexer & Compiler
17896      */
17897     
17898     var InlineLexer  = function (links, options) {
17899       this.options = options || marked.defaults;
17900       this.links = links;
17901       this.rules = inline.normal;
17902       this.renderer = this.options.renderer || new Renderer;
17903       this.renderer.options = this.options;
17904     
17905       if (!this.links) {
17906         throw new
17907           Error('Tokens array requires a `links` property.');
17908       }
17909     
17910       if (this.options.gfm) {
17911         if (this.options.breaks) {
17912           this.rules = inline.breaks;
17913         } else {
17914           this.rules = inline.gfm;
17915         }
17916       } else if (this.options.pedantic) {
17917         this.rules = inline.pedantic;
17918       }
17919     }
17920     
17921     /**
17922      * Expose Inline Rules
17923      */
17924     
17925     InlineLexer.rules = inline;
17926     
17927     /**
17928      * Static Lexing/Compiling Method
17929      */
17930     
17931     InlineLexer.output = function(src, links, options) {
17932       var inline = new InlineLexer(links, options);
17933       return inline.output(src);
17934     };
17935     
17936     /**
17937      * Lexing/Compiling
17938      */
17939     
17940     InlineLexer.prototype.output = function(src) {
17941       var out = ''
17942         , link
17943         , text
17944         , href
17945         , cap;
17946     
17947       while (src) {
17948         // escape
17949         if (cap = this.rules.escape.exec(src)) {
17950           src = src.substring(cap[0].length);
17951           out += cap[1];
17952           continue;
17953         }
17954     
17955         // autolink
17956         if (cap = this.rules.autolink.exec(src)) {
17957           src = src.substring(cap[0].length);
17958           if (cap[2] === '@') {
17959             text = cap[1].charAt(6) === ':'
17960               ? this.mangle(cap[1].substring(7))
17961               : this.mangle(cap[1]);
17962             href = this.mangle('mailto:') + text;
17963           } else {
17964             text = escape(cap[1]);
17965             href = text;
17966           }
17967           out += this.renderer.link(href, null, text);
17968           continue;
17969         }
17970     
17971         // url (gfm)
17972         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17973           src = src.substring(cap[0].length);
17974           text = escape(cap[1]);
17975           href = text;
17976           out += this.renderer.link(href, null, text);
17977           continue;
17978         }
17979     
17980         // tag
17981         if (cap = this.rules.tag.exec(src)) {
17982           if (!this.inLink && /^<a /i.test(cap[0])) {
17983             this.inLink = true;
17984           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17985             this.inLink = false;
17986           }
17987           src = src.substring(cap[0].length);
17988           out += this.options.sanitize
17989             ? this.options.sanitizer
17990               ? this.options.sanitizer(cap[0])
17991               : escape(cap[0])
17992             : cap[0];
17993           continue;
17994         }
17995     
17996         // link
17997         if (cap = this.rules.link.exec(src)) {
17998           src = src.substring(cap[0].length);
17999           this.inLink = true;
18000           out += this.outputLink(cap, {
18001             href: cap[2],
18002             title: cap[3]
18003           });
18004           this.inLink = false;
18005           continue;
18006         }
18007     
18008         // reflink, nolink
18009         if ((cap = this.rules.reflink.exec(src))
18010             || (cap = this.rules.nolink.exec(src))) {
18011           src = src.substring(cap[0].length);
18012           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18013           link = this.links[link.toLowerCase()];
18014           if (!link || !link.href) {
18015             out += cap[0].charAt(0);
18016             src = cap[0].substring(1) + src;
18017             continue;
18018           }
18019           this.inLink = true;
18020           out += this.outputLink(cap, link);
18021           this.inLink = false;
18022           continue;
18023         }
18024     
18025         // strong
18026         if (cap = this.rules.strong.exec(src)) {
18027           src = src.substring(cap[0].length);
18028           out += this.renderer.strong(this.output(cap[2] || cap[1]));
18029           continue;
18030         }
18031     
18032         // em
18033         if (cap = this.rules.em.exec(src)) {
18034           src = src.substring(cap[0].length);
18035           out += this.renderer.em(this.output(cap[2] || cap[1]));
18036           continue;
18037         }
18038     
18039         // code
18040         if (cap = this.rules.code.exec(src)) {
18041           src = src.substring(cap[0].length);
18042           out += this.renderer.codespan(escape(cap[2], true));
18043           continue;
18044         }
18045     
18046         // br
18047         if (cap = this.rules.br.exec(src)) {
18048           src = src.substring(cap[0].length);
18049           out += this.renderer.br();
18050           continue;
18051         }
18052     
18053         // del (gfm)
18054         if (cap = this.rules.del.exec(src)) {
18055           src = src.substring(cap[0].length);
18056           out += this.renderer.del(this.output(cap[1]));
18057           continue;
18058         }
18059     
18060         // text
18061         if (cap = this.rules.text.exec(src)) {
18062           src = src.substring(cap[0].length);
18063           out += this.renderer.text(escape(this.smartypants(cap[0])));
18064           continue;
18065         }
18066     
18067         if (src) {
18068           throw new
18069             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18070         }
18071       }
18072     
18073       return out;
18074     };
18075     
18076     /**
18077      * Compile Link
18078      */
18079     
18080     InlineLexer.prototype.outputLink = function(cap, link) {
18081       var href = escape(link.href)
18082         , title = link.title ? escape(link.title) : null;
18083     
18084       return cap[0].charAt(0) !== '!'
18085         ? this.renderer.link(href, title, this.output(cap[1]))
18086         : this.renderer.image(href, title, escape(cap[1]));
18087     };
18088     
18089     /**
18090      * Smartypants Transformations
18091      */
18092     
18093     InlineLexer.prototype.smartypants = function(text) {
18094       if (!this.options.smartypants)  { return text; }
18095       return text
18096         // em-dashes
18097         .replace(/---/g, '\u2014')
18098         // en-dashes
18099         .replace(/--/g, '\u2013')
18100         // opening singles
18101         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18102         // closing singles & apostrophes
18103         .replace(/'/g, '\u2019')
18104         // opening doubles
18105         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18106         // closing doubles
18107         .replace(/"/g, '\u201d')
18108         // ellipses
18109         .replace(/\.{3}/g, '\u2026');
18110     };
18111     
18112     /**
18113      * Mangle Links
18114      */
18115     
18116     InlineLexer.prototype.mangle = function(text) {
18117       if (!this.options.mangle) { return text; }
18118       var out = ''
18119         , l = text.length
18120         , i = 0
18121         , ch;
18122     
18123       for (; i < l; i++) {
18124         ch = text.charCodeAt(i);
18125         if (Math.random() > 0.5) {
18126           ch = 'x' + ch.toString(16);
18127         }
18128         out += '&#' + ch + ';';
18129       }
18130     
18131       return out;
18132     };
18133     
18134     /**
18135      * Renderer
18136      */
18137     
18138      /**
18139          * eval:var:Renderer
18140     */
18141     
18142     var Renderer   = function (options) {
18143       this.options = options || {};
18144     }
18145     
18146     Renderer.prototype.code = function(code, lang, escaped) {
18147       if (this.options.highlight) {
18148         var out = this.options.highlight(code, lang);
18149         if (out != null && out !== code) {
18150           escaped = true;
18151           code = out;
18152         }
18153       } else {
18154             // hack!!! - it's already escapeD?
18155             escaped = true;
18156       }
18157     
18158       if (!lang) {
18159         return '<pre><code>'
18160           + (escaped ? code : escape(code, true))
18161           + '\n</code></pre>';
18162       }
18163     
18164       return '<pre><code class="'
18165         + this.options.langPrefix
18166         + escape(lang, true)
18167         + '">'
18168         + (escaped ? code : escape(code, true))
18169         + '\n</code></pre>\n';
18170     };
18171     
18172     Renderer.prototype.blockquote = function(quote) {
18173       return '<blockquote>\n' + quote + '</blockquote>\n';
18174     };
18175     
18176     Renderer.prototype.html = function(html) {
18177       return html;
18178     };
18179     
18180     Renderer.prototype.heading = function(text, level, raw) {
18181       return '<h'
18182         + level
18183         + ' id="'
18184         + this.options.headerPrefix
18185         + raw.toLowerCase().replace(/[^\w]+/g, '-')
18186         + '">'
18187         + text
18188         + '</h'
18189         + level
18190         + '>\n';
18191     };
18192     
18193     Renderer.prototype.hr = function() {
18194       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18195     };
18196     
18197     Renderer.prototype.list = function(body, ordered) {
18198       var type = ordered ? 'ol' : 'ul';
18199       return '<' + type + '>\n' + body + '</' + type + '>\n';
18200     };
18201     
18202     Renderer.prototype.listitem = function(text) {
18203       return '<li>' + text + '</li>\n';
18204     };
18205     
18206     Renderer.prototype.paragraph = function(text) {
18207       return '<p>' + text + '</p>\n';
18208     };
18209     
18210     Renderer.prototype.table = function(header, body) {
18211       return '<table class="table table-striped">\n'
18212         + '<thead>\n'
18213         + header
18214         + '</thead>\n'
18215         + '<tbody>\n'
18216         + body
18217         + '</tbody>\n'
18218         + '</table>\n';
18219     };
18220     
18221     Renderer.prototype.tablerow = function(content) {
18222       return '<tr>\n' + content + '</tr>\n';
18223     };
18224     
18225     Renderer.prototype.tablecell = function(content, flags) {
18226       var type = flags.header ? 'th' : 'td';
18227       var tag = flags.align
18228         ? '<' + type + ' style="text-align:' + flags.align + '">'
18229         : '<' + type + '>';
18230       return tag + content + '</' + type + '>\n';
18231     };
18232     
18233     // span level renderer
18234     Renderer.prototype.strong = function(text) {
18235       return '<strong>' + text + '</strong>';
18236     };
18237     
18238     Renderer.prototype.em = function(text) {
18239       return '<em>' + text + '</em>';
18240     };
18241     
18242     Renderer.prototype.codespan = function(text) {
18243       return '<code>' + text + '</code>';
18244     };
18245     
18246     Renderer.prototype.br = function() {
18247       return this.options.xhtml ? '<br/>' : '<br>';
18248     };
18249     
18250     Renderer.prototype.del = function(text) {
18251       return '<del>' + text + '</del>';
18252     };
18253     
18254     Renderer.prototype.link = function(href, title, text) {
18255       if (this.options.sanitize) {
18256         try {
18257           var prot = decodeURIComponent(unescape(href))
18258             .replace(/[^\w:]/g, '')
18259             .toLowerCase();
18260         } catch (e) {
18261           return '';
18262         }
18263         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18264           return '';
18265         }
18266       }
18267       var out = '<a href="' + href + '"';
18268       if (title) {
18269         out += ' title="' + title + '"';
18270       }
18271       out += '>' + text + '</a>';
18272       return out;
18273     };
18274     
18275     Renderer.prototype.image = function(href, title, text) {
18276       var out = '<img src="' + href + '" alt="' + text + '"';
18277       if (title) {
18278         out += ' title="' + title + '"';
18279       }
18280       out += this.options.xhtml ? '/>' : '>';
18281       return out;
18282     };
18283     
18284     Renderer.prototype.text = function(text) {
18285       return text;
18286     };
18287     
18288     /**
18289      * Parsing & Compiling
18290      */
18291          /**
18292          * eval:var:Parser
18293     */
18294     
18295     var Parser= function (options) {
18296       this.tokens = [];
18297       this.token = null;
18298       this.options = options || marked.defaults;
18299       this.options.renderer = this.options.renderer || new Renderer;
18300       this.renderer = this.options.renderer;
18301       this.renderer.options = this.options;
18302     }
18303     
18304     /**
18305      * Static Parse Method
18306      */
18307     
18308     Parser.parse = function(src, options, renderer) {
18309       var parser = new Parser(options, renderer);
18310       return parser.parse(src);
18311     };
18312     
18313     /**
18314      * Parse Loop
18315      */
18316     
18317     Parser.prototype.parse = function(src) {
18318       this.inline = new InlineLexer(src.links, this.options, this.renderer);
18319       this.tokens = src.reverse();
18320     
18321       var out = '';
18322       while (this.next()) {
18323         out += this.tok();
18324       }
18325     
18326       return out;
18327     };
18328     
18329     /**
18330      * Next Token
18331      */
18332     
18333     Parser.prototype.next = function() {
18334       return this.token = this.tokens.pop();
18335     };
18336     
18337     /**
18338      * Preview Next Token
18339      */
18340     
18341     Parser.prototype.peek = function() {
18342       return this.tokens[this.tokens.length - 1] || 0;
18343     };
18344     
18345     /**
18346      * Parse Text Tokens
18347      */
18348     
18349     Parser.prototype.parseText = function() {
18350       var body = this.token.text;
18351     
18352       while (this.peek().type === 'text') {
18353         body += '\n' + this.next().text;
18354       }
18355     
18356       return this.inline.output(body);
18357     };
18358     
18359     /**
18360      * Parse Current Token
18361      */
18362     
18363     Parser.prototype.tok = function() {
18364       switch (this.token.type) {
18365         case 'space': {
18366           return '';
18367         }
18368         case 'hr': {
18369           return this.renderer.hr();
18370         }
18371         case 'heading': {
18372           return this.renderer.heading(
18373             this.inline.output(this.token.text),
18374             this.token.depth,
18375             this.token.text);
18376         }
18377         case 'code': {
18378           return this.renderer.code(this.token.text,
18379             this.token.lang,
18380             this.token.escaped);
18381         }
18382         case 'table': {
18383           var header = ''
18384             , body = ''
18385             , i
18386             , row
18387             , cell
18388             , flags
18389             , j;
18390     
18391           // header
18392           cell = '';
18393           for (i = 0; i < this.token.header.length; i++) {
18394             flags = { header: true, align: this.token.align[i] };
18395             cell += this.renderer.tablecell(
18396               this.inline.output(this.token.header[i]),
18397               { header: true, align: this.token.align[i] }
18398             );
18399           }
18400           header += this.renderer.tablerow(cell);
18401     
18402           for (i = 0; i < this.token.cells.length; i++) {
18403             row = this.token.cells[i];
18404     
18405             cell = '';
18406             for (j = 0; j < row.length; j++) {
18407               cell += this.renderer.tablecell(
18408                 this.inline.output(row[j]),
18409                 { header: false, align: this.token.align[j] }
18410               );
18411             }
18412     
18413             body += this.renderer.tablerow(cell);
18414           }
18415           return this.renderer.table(header, body);
18416         }
18417         case 'blockquote_start': {
18418           var body = '';
18419     
18420           while (this.next().type !== 'blockquote_end') {
18421             body += this.tok();
18422           }
18423     
18424           return this.renderer.blockquote(body);
18425         }
18426         case 'list_start': {
18427           var body = ''
18428             , ordered = this.token.ordered;
18429     
18430           while (this.next().type !== 'list_end') {
18431             body += this.tok();
18432           }
18433     
18434           return this.renderer.list(body, ordered);
18435         }
18436         case 'list_item_start': {
18437           var body = '';
18438     
18439           while (this.next().type !== 'list_item_end') {
18440             body += this.token.type === 'text'
18441               ? this.parseText()
18442               : this.tok();
18443           }
18444     
18445           return this.renderer.listitem(body);
18446         }
18447         case 'loose_item_start': {
18448           var body = '';
18449     
18450           while (this.next().type !== 'list_item_end') {
18451             body += this.tok();
18452           }
18453     
18454           return this.renderer.listitem(body);
18455         }
18456         case 'html': {
18457           var html = !this.token.pre && !this.options.pedantic
18458             ? this.inline.output(this.token.text)
18459             : this.token.text;
18460           return this.renderer.html(html);
18461         }
18462         case 'paragraph': {
18463           return this.renderer.paragraph(this.inline.output(this.token.text));
18464         }
18465         case 'text': {
18466           return this.renderer.paragraph(this.parseText());
18467         }
18468       }
18469     };
18470   
18471     
18472     /**
18473      * Marked
18474      */
18475          /**
18476          * eval:var:marked
18477     */
18478     var marked = function (src, opt, callback) {
18479       if (callback || typeof opt === 'function') {
18480         if (!callback) {
18481           callback = opt;
18482           opt = null;
18483         }
18484     
18485         opt = merge({}, marked.defaults, opt || {});
18486     
18487         var highlight = opt.highlight
18488           , tokens
18489           , pending
18490           , i = 0;
18491     
18492         try {
18493           tokens = Lexer.lex(src, opt)
18494         } catch (e) {
18495           return callback(e);
18496         }
18497     
18498         pending = tokens.length;
18499          /**
18500          * eval:var:done
18501     */
18502         var done = function(err) {
18503           if (err) {
18504             opt.highlight = highlight;
18505             return callback(err);
18506           }
18507     
18508           var out;
18509     
18510           try {
18511             out = Parser.parse(tokens, opt);
18512           } catch (e) {
18513             err = e;
18514           }
18515     
18516           opt.highlight = highlight;
18517     
18518           return err
18519             ? callback(err)
18520             : callback(null, out);
18521         };
18522     
18523         if (!highlight || highlight.length < 3) {
18524           return done();
18525         }
18526     
18527         delete opt.highlight;
18528     
18529         if (!pending) { return done(); }
18530     
18531         for (; i < tokens.length; i++) {
18532           (function(token) {
18533             if (token.type !== 'code') {
18534               return --pending || done();
18535             }
18536             return highlight(token.text, token.lang, function(err, code) {
18537               if (err) { return done(err); }
18538               if (code == null || code === token.text) {
18539                 return --pending || done();
18540               }
18541               token.text = code;
18542               token.escaped = true;
18543               --pending || done();
18544             });
18545           })(tokens[i]);
18546         }
18547     
18548         return;
18549       }
18550       try {
18551         if (opt) { opt = merge({}, marked.defaults, opt); }
18552         return Parser.parse(Lexer.lex(src, opt), opt);
18553       } catch (e) {
18554         e.message += '\nPlease report this to https://github.com/chjj/marked.';
18555         if ((opt || marked.defaults).silent) {
18556           return '<p>An error occured:</p><pre>'
18557             + escape(e.message + '', true)
18558             + '</pre>';
18559         }
18560         throw e;
18561       }
18562     }
18563     
18564     /**
18565      * Options
18566      */
18567     
18568     marked.options =
18569     marked.setOptions = function(opt) {
18570       merge(marked.defaults, opt);
18571       return marked;
18572     };
18573     
18574     marked.defaults = {
18575       gfm: true,
18576       tables: true,
18577       breaks: false,
18578       pedantic: false,
18579       sanitize: false,
18580       sanitizer: null,
18581       mangle: true,
18582       smartLists: false,
18583       silent: false,
18584       highlight: null,
18585       langPrefix: 'lang-',
18586       smartypants: false,
18587       headerPrefix: '',
18588       renderer: new Renderer,
18589       xhtml: false
18590     };
18591     
18592     /**
18593      * Expose
18594      */
18595     
18596     marked.Parser = Parser;
18597     marked.parser = Parser.parse;
18598     
18599     marked.Renderer = Renderer;
18600     
18601     marked.Lexer = Lexer;
18602     marked.lexer = Lexer.lex;
18603     
18604     marked.InlineLexer = InlineLexer;
18605     marked.inlineLexer = InlineLexer.output;
18606     
18607     marked.parse = marked;
18608     
18609     Roo.Markdown.marked = marked;
18610
18611 })();/*
18612  * Based on:
18613  * Ext JS Library 1.1.1
18614  * Copyright(c) 2006-2007, Ext JS, LLC.
18615  *
18616  * Originally Released Under LGPL - original licence link has changed is not relivant.
18617  *
18618  * Fork - LGPL
18619  * <script type="text/javascript">
18620  */
18621
18622
18623
18624 /*
18625  * These classes are derivatives of the similarly named classes in the YUI Library.
18626  * The original license:
18627  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18628  * Code licensed under the BSD License:
18629  * http://developer.yahoo.net/yui/license.txt
18630  */
18631
18632 (function() {
18633
18634 var Event=Roo.EventManager;
18635 var Dom=Roo.lib.Dom;
18636
18637 /**
18638  * @class Roo.dd.DragDrop
18639  * @extends Roo.util.Observable
18640  * Defines the interface and base operation of items that that can be
18641  * dragged or can be drop targets.  It was designed to be extended, overriding
18642  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18643  * Up to three html elements can be associated with a DragDrop instance:
18644  * <ul>
18645  * <li>linked element: the element that is passed into the constructor.
18646  * This is the element which defines the boundaries for interaction with
18647  * other DragDrop objects.</li>
18648  * <li>handle element(s): The drag operation only occurs if the element that
18649  * was clicked matches a handle element.  By default this is the linked
18650  * element, but there are times that you will want only a portion of the
18651  * linked element to initiate the drag operation, and the setHandleElId()
18652  * method provides a way to define this.</li>
18653  * <li>drag element: this represents the element that would be moved along
18654  * with the cursor during a drag operation.  By default, this is the linked
18655  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18656  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18657  * </li>
18658  * </ul>
18659  * This class should not be instantiated until the onload event to ensure that
18660  * the associated elements are available.
18661  * The following would define a DragDrop obj that would interact with any
18662  * other DragDrop obj in the "group1" group:
18663  * <pre>
18664  *  dd = new Roo.dd.DragDrop("div1", "group1");
18665  * </pre>
18666  * Since none of the event handlers have been implemented, nothing would
18667  * actually happen if you were to run the code above.  Normally you would
18668  * override this class or one of the default implementations, but you can
18669  * also override the methods you want on an instance of the class...
18670  * <pre>
18671  *  dd.onDragDrop = function(e, id) {
18672  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18673  *  }
18674  * </pre>
18675  * @constructor
18676  * @param {String} id of the element that is linked to this instance
18677  * @param {String} sGroup the group of related DragDrop objects
18678  * @param {object} config an object containing configurable attributes
18679  *                Valid properties for DragDrop:
18680  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18681  */
18682 Roo.dd.DragDrop = function(id, sGroup, config) {
18683     if (id) {
18684         this.init(id, sGroup, config);
18685     }
18686     
18687 };
18688
18689 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18690
18691     /**
18692      * The id of the element associated with this object.  This is what we
18693      * refer to as the "linked element" because the size and position of
18694      * this element is used to determine when the drag and drop objects have
18695      * interacted.
18696      * @property id
18697      * @type String
18698      */
18699     id: null,
18700
18701     /**
18702      * Configuration attributes passed into the constructor
18703      * @property config
18704      * @type object
18705      */
18706     config: null,
18707
18708     /**
18709      * The id of the element that will be dragged.  By default this is same
18710      * as the linked element , but could be changed to another element. Ex:
18711      * Roo.dd.DDProxy
18712      * @property dragElId
18713      * @type String
18714      * @private
18715      */
18716     dragElId: null,
18717
18718     /**
18719      * the id of the element that initiates the drag operation.  By default
18720      * this is the linked element, but could be changed to be a child of this
18721      * element.  This lets us do things like only starting the drag when the
18722      * header element within the linked html element is clicked.
18723      * @property handleElId
18724      * @type String
18725      * @private
18726      */
18727     handleElId: null,
18728
18729     /**
18730      * An associative array of HTML tags that will be ignored if clicked.
18731      * @property invalidHandleTypes
18732      * @type {string: string}
18733      */
18734     invalidHandleTypes: null,
18735
18736     /**
18737      * An associative array of ids for elements that will be ignored if clicked
18738      * @property invalidHandleIds
18739      * @type {string: string}
18740      */
18741     invalidHandleIds: null,
18742
18743     /**
18744      * An indexted array of css class names for elements that will be ignored
18745      * if clicked.
18746      * @property invalidHandleClasses
18747      * @type string[]
18748      */
18749     invalidHandleClasses: null,
18750
18751     /**
18752      * The linked element's absolute X position at the time the drag was
18753      * started
18754      * @property startPageX
18755      * @type int
18756      * @private
18757      */
18758     startPageX: 0,
18759
18760     /**
18761      * The linked element's absolute X position at the time the drag was
18762      * started
18763      * @property startPageY
18764      * @type int
18765      * @private
18766      */
18767     startPageY: 0,
18768
18769     /**
18770      * The group defines a logical collection of DragDrop objects that are
18771      * related.  Instances only get events when interacting with other
18772      * DragDrop object in the same group.  This lets us define multiple
18773      * groups using a single DragDrop subclass if we want.
18774      * @property groups
18775      * @type {string: string}
18776      */
18777     groups: null,
18778
18779     /**
18780      * Individual drag/drop instances can be locked.  This will prevent
18781      * onmousedown start drag.
18782      * @property locked
18783      * @type boolean
18784      * @private
18785      */
18786     locked: false,
18787
18788     /**
18789      * Lock this instance
18790      * @method lock
18791      */
18792     lock: function() { this.locked = true; },
18793
18794     /**
18795      * Unlock this instace
18796      * @method unlock
18797      */
18798     unlock: function() { this.locked = false; },
18799
18800     /**
18801      * By default, all insances can be a drop target.  This can be disabled by
18802      * setting isTarget to false.
18803      * @method isTarget
18804      * @type boolean
18805      */
18806     isTarget: true,
18807
18808     /**
18809      * The padding configured for this drag and drop object for calculating
18810      * the drop zone intersection with this object.
18811      * @method padding
18812      * @type int[]
18813      */
18814     padding: null,
18815
18816     /**
18817      * Cached reference to the linked element
18818      * @property _domRef
18819      * @private
18820      */
18821     _domRef: null,
18822
18823     /**
18824      * Internal typeof flag
18825      * @property __ygDragDrop
18826      * @private
18827      */
18828     __ygDragDrop: true,
18829
18830     /**
18831      * Set to true when horizontal contraints are applied
18832      * @property constrainX
18833      * @type boolean
18834      * @private
18835      */
18836     constrainX: false,
18837
18838     /**
18839      * Set to true when vertical contraints are applied
18840      * @property constrainY
18841      * @type boolean
18842      * @private
18843      */
18844     constrainY: false,
18845
18846     /**
18847      * The left constraint
18848      * @property minX
18849      * @type int
18850      * @private
18851      */
18852     minX: 0,
18853
18854     /**
18855      * The right constraint
18856      * @property maxX
18857      * @type int
18858      * @private
18859      */
18860     maxX: 0,
18861
18862     /**
18863      * The up constraint
18864      * @property minY
18865      * @type int
18866      * @type int
18867      * @private
18868      */
18869     minY: 0,
18870
18871     /**
18872      * The down constraint
18873      * @property maxY
18874      * @type int
18875      * @private
18876      */
18877     maxY: 0,
18878
18879     /**
18880      * Maintain offsets when we resetconstraints.  Set to true when you want
18881      * the position of the element relative to its parent to stay the same
18882      * when the page changes
18883      *
18884      * @property maintainOffset
18885      * @type boolean
18886      */
18887     maintainOffset: false,
18888
18889     /**
18890      * Array of pixel locations the element will snap to if we specified a
18891      * horizontal graduation/interval.  This array is generated automatically
18892      * when you define a tick interval.
18893      * @property xTicks
18894      * @type int[]
18895      */
18896     xTicks: null,
18897
18898     /**
18899      * Array of pixel locations the element will snap to if we specified a
18900      * vertical graduation/interval.  This array is generated automatically
18901      * when you define a tick interval.
18902      * @property yTicks
18903      * @type int[]
18904      */
18905     yTicks: null,
18906
18907     /**
18908      * By default the drag and drop instance will only respond to the primary
18909      * button click (left button for a right-handed mouse).  Set to true to
18910      * allow drag and drop to start with any mouse click that is propogated
18911      * by the browser
18912      * @property primaryButtonOnly
18913      * @type boolean
18914      */
18915     primaryButtonOnly: true,
18916
18917     /**
18918      * The availabe property is false until the linked dom element is accessible.
18919      * @property available
18920      * @type boolean
18921      */
18922     available: false,
18923
18924     /**
18925      * By default, drags can only be initiated if the mousedown occurs in the
18926      * region the linked element is.  This is done in part to work around a
18927      * bug in some browsers that mis-report the mousedown if the previous
18928      * mouseup happened outside of the window.  This property is set to true
18929      * if outer handles are defined.
18930      *
18931      * @property hasOuterHandles
18932      * @type boolean
18933      * @default false
18934      */
18935     hasOuterHandles: false,
18936
18937     /**
18938      * Code that executes immediately before the startDrag event
18939      * @method b4StartDrag
18940      * @private
18941      */
18942     b4StartDrag: function(x, y) { },
18943
18944     /**
18945      * Abstract method called after a drag/drop object is clicked
18946      * and the drag or mousedown time thresholds have beeen met.
18947      * @method startDrag
18948      * @param {int} X click location
18949      * @param {int} Y click location
18950      */
18951     startDrag: function(x, y) { /* override this */ },
18952
18953     /**
18954      * Code that executes immediately before the onDrag event
18955      * @method b4Drag
18956      * @private
18957      */
18958     b4Drag: function(e) { },
18959
18960     /**
18961      * Abstract method called during the onMouseMove event while dragging an
18962      * object.
18963      * @method onDrag
18964      * @param {Event} e the mousemove event
18965      */
18966     onDrag: function(e) { /* override this */ },
18967
18968     /**
18969      * Abstract method called when this element fist begins hovering over
18970      * another DragDrop obj
18971      * @method onDragEnter
18972      * @param {Event} e the mousemove event
18973      * @param {String|DragDrop[]} id In POINT mode, the element
18974      * id this is hovering over.  In INTERSECT mode, an array of one or more
18975      * dragdrop items being hovered over.
18976      */
18977     onDragEnter: function(e, id) { /* override this */ },
18978
18979     /**
18980      * Code that executes immediately before the onDragOver event
18981      * @method b4DragOver
18982      * @private
18983      */
18984     b4DragOver: function(e) { },
18985
18986     /**
18987      * Abstract method called when this element is hovering over another
18988      * DragDrop obj
18989      * @method onDragOver
18990      * @param {Event} e the mousemove event
18991      * @param {String|DragDrop[]} id In POINT mode, the element
18992      * id this is hovering over.  In INTERSECT mode, an array of dd items
18993      * being hovered over.
18994      */
18995     onDragOver: function(e, id) { /* override this */ },
18996
18997     /**
18998      * Code that executes immediately before the onDragOut event
18999      * @method b4DragOut
19000      * @private
19001      */
19002     b4DragOut: function(e) { },
19003
19004     /**
19005      * Abstract method called when we are no longer hovering over an element
19006      * @method onDragOut
19007      * @param {Event} e the mousemove event
19008      * @param {String|DragDrop[]} id In POINT mode, the element
19009      * id this was hovering over.  In INTERSECT mode, an array of dd items
19010      * that the mouse is no longer over.
19011      */
19012     onDragOut: function(e, id) { /* override this */ },
19013
19014     /**
19015      * Code that executes immediately before the onDragDrop event
19016      * @method b4DragDrop
19017      * @private
19018      */
19019     b4DragDrop: function(e) { },
19020
19021     /**
19022      * Abstract method called when this item is dropped on another DragDrop
19023      * obj
19024      * @method onDragDrop
19025      * @param {Event} e the mouseup event
19026      * @param {String|DragDrop[]} id In POINT mode, the element
19027      * id this was dropped on.  In INTERSECT mode, an array of dd items this
19028      * was dropped on.
19029      */
19030     onDragDrop: function(e, id) { /* override this */ },
19031
19032     /**
19033      * Abstract method called when this item is dropped on an area with no
19034      * drop target
19035      * @method onInvalidDrop
19036      * @param {Event} e the mouseup event
19037      */
19038     onInvalidDrop: function(e) { /* override this */ },
19039
19040     /**
19041      * Code that executes immediately before the endDrag event
19042      * @method b4EndDrag
19043      * @private
19044      */
19045     b4EndDrag: function(e) { },
19046
19047     /**
19048      * Fired when we are done dragging the object
19049      * @method endDrag
19050      * @param {Event} e the mouseup event
19051      */
19052     endDrag: function(e) { /* override this */ },
19053
19054     /**
19055      * Code executed immediately before the onMouseDown event
19056      * @method b4MouseDown
19057      * @param {Event} e the mousedown event
19058      * @private
19059      */
19060     b4MouseDown: function(e) {  },
19061
19062     /**
19063      * Event handler that fires when a drag/drop obj gets a mousedown
19064      * @method onMouseDown
19065      * @param {Event} e the mousedown event
19066      */
19067     onMouseDown: function(e) { /* override this */ },
19068
19069     /**
19070      * Event handler that fires when a drag/drop obj gets a mouseup
19071      * @method onMouseUp
19072      * @param {Event} e the mouseup event
19073      */
19074     onMouseUp: function(e) { /* override this */ },
19075
19076     /**
19077      * Override the onAvailable method to do what is needed after the initial
19078      * position was determined.
19079      * @method onAvailable
19080      */
19081     onAvailable: function () {
19082     },
19083
19084     /*
19085      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19086      * @type Object
19087      */
19088     defaultPadding : {left:0, right:0, top:0, bottom:0},
19089
19090     /*
19091      * Initializes the drag drop object's constraints to restrict movement to a certain element.
19092  *
19093  * Usage:
19094  <pre><code>
19095  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19096                 { dragElId: "existingProxyDiv" });
19097  dd.startDrag = function(){
19098      this.constrainTo("parent-id");
19099  };
19100  </code></pre>
19101  * Or you can initalize it using the {@link Roo.Element} object:
19102  <pre><code>
19103  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19104      startDrag : function(){
19105          this.constrainTo("parent-id");
19106      }
19107  });
19108  </code></pre>
19109      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19110      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19111      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19112      * an object containing the sides to pad. For example: {right:10, bottom:10}
19113      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19114      */
19115     constrainTo : function(constrainTo, pad, inContent){
19116         if(typeof pad == "number"){
19117             pad = {left: pad, right:pad, top:pad, bottom:pad};
19118         }
19119         pad = pad || this.defaultPadding;
19120         var b = Roo.get(this.getEl()).getBox();
19121         var ce = Roo.get(constrainTo);
19122         var s = ce.getScroll();
19123         var c, cd = ce.dom;
19124         if(cd == document.body){
19125             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19126         }else{
19127             xy = ce.getXY();
19128             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19129         }
19130
19131
19132         var topSpace = b.y - c.y;
19133         var leftSpace = b.x - c.x;
19134
19135         this.resetConstraints();
19136         this.setXConstraint(leftSpace - (pad.left||0), // left
19137                 c.width - leftSpace - b.width - (pad.right||0) //right
19138         );
19139         this.setYConstraint(topSpace - (pad.top||0), //top
19140                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19141         );
19142     },
19143
19144     /**
19145      * Returns a reference to the linked element
19146      * @method getEl
19147      * @return {HTMLElement} the html element
19148      */
19149     getEl: function() {
19150         if (!this._domRef) {
19151             this._domRef = Roo.getDom(this.id);
19152         }
19153
19154         return this._domRef;
19155     },
19156
19157     /**
19158      * Returns a reference to the actual element to drag.  By default this is
19159      * the same as the html element, but it can be assigned to another
19160      * element. An example of this can be found in Roo.dd.DDProxy
19161      * @method getDragEl
19162      * @return {HTMLElement} the html element
19163      */
19164     getDragEl: function() {
19165         return Roo.getDom(this.dragElId);
19166     },
19167
19168     /**
19169      * Sets up the DragDrop object.  Must be called in the constructor of any
19170      * Roo.dd.DragDrop subclass
19171      * @method init
19172      * @param id the id of the linked element
19173      * @param {String} sGroup the group of related items
19174      * @param {object} config configuration attributes
19175      */
19176     init: function(id, sGroup, config) {
19177         this.initTarget(id, sGroup, config);
19178         if (!Roo.isTouch) {
19179             Event.on(this.id, "mousedown", this.handleMouseDown, this);
19180         }
19181         Event.on(this.id, "touchstart", this.handleMouseDown, this);
19182         // Event.on(this.id, "selectstart", Event.preventDefault);
19183     },
19184
19185     /**
19186      * Initializes Targeting functionality only... the object does not
19187      * get a mousedown handler.
19188      * @method initTarget
19189      * @param id the id of the linked element
19190      * @param {String} sGroup the group of related items
19191      * @param {object} config configuration attributes
19192      */
19193     initTarget: function(id, sGroup, config) {
19194
19195         // configuration attributes
19196         this.config = config || {};
19197
19198         // create a local reference to the drag and drop manager
19199         this.DDM = Roo.dd.DDM;
19200         // initialize the groups array
19201         this.groups = {};
19202
19203         // assume that we have an element reference instead of an id if the
19204         // parameter is not a string
19205         if (typeof id !== "string") {
19206             id = Roo.id(id);
19207         }
19208
19209         // set the id
19210         this.id = id;
19211
19212         // add to an interaction group
19213         this.addToGroup((sGroup) ? sGroup : "default");
19214
19215         // We don't want to register this as the handle with the manager
19216         // so we just set the id rather than calling the setter.
19217         this.handleElId = id;
19218
19219         // the linked element is the element that gets dragged by default
19220         this.setDragElId(id);
19221
19222         // by default, clicked anchors will not start drag operations.
19223         this.invalidHandleTypes = { A: "A" };
19224         this.invalidHandleIds = {};
19225         this.invalidHandleClasses = [];
19226
19227         this.applyConfig();
19228
19229         this.handleOnAvailable();
19230     },
19231
19232     /**
19233      * Applies the configuration parameters that were passed into the constructor.
19234      * This is supposed to happen at each level through the inheritance chain.  So
19235      * a DDProxy implentation will execute apply config on DDProxy, DD, and
19236      * DragDrop in order to get all of the parameters that are available in
19237      * each object.
19238      * @method applyConfig
19239      */
19240     applyConfig: function() {
19241
19242         // configurable properties:
19243         //    padding, isTarget, maintainOffset, primaryButtonOnly
19244         this.padding           = this.config.padding || [0, 0, 0, 0];
19245         this.isTarget          = (this.config.isTarget !== false);
19246         this.maintainOffset    = (this.config.maintainOffset);
19247         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19248
19249     },
19250
19251     /**
19252      * Executed when the linked element is available
19253      * @method handleOnAvailable
19254      * @private
19255      */
19256     handleOnAvailable: function() {
19257         this.available = true;
19258         this.resetConstraints();
19259         this.onAvailable();
19260     },
19261
19262      /**
19263      * Configures the padding for the target zone in px.  Effectively expands
19264      * (or reduces) the virtual object size for targeting calculations.
19265      * Supports css-style shorthand; if only one parameter is passed, all sides
19266      * will have that padding, and if only two are passed, the top and bottom
19267      * will have the first param, the left and right the second.
19268      * @method setPadding
19269      * @param {int} iTop    Top pad
19270      * @param {int} iRight  Right pad
19271      * @param {int} iBot    Bot pad
19272      * @param {int} iLeft   Left pad
19273      */
19274     setPadding: function(iTop, iRight, iBot, iLeft) {
19275         // this.padding = [iLeft, iRight, iTop, iBot];
19276         if (!iRight && 0 !== iRight) {
19277             this.padding = [iTop, iTop, iTop, iTop];
19278         } else if (!iBot && 0 !== iBot) {
19279             this.padding = [iTop, iRight, iTop, iRight];
19280         } else {
19281             this.padding = [iTop, iRight, iBot, iLeft];
19282         }
19283     },
19284
19285     /**
19286      * Stores the initial placement of the linked element.
19287      * @method setInitialPosition
19288      * @param {int} diffX   the X offset, default 0
19289      * @param {int} diffY   the Y offset, default 0
19290      */
19291     setInitPosition: function(diffX, diffY) {
19292         var el = this.getEl();
19293
19294         if (!this.DDM.verifyEl(el)) {
19295             return;
19296         }
19297
19298         var dx = diffX || 0;
19299         var dy = diffY || 0;
19300
19301         var p = Dom.getXY( el );
19302
19303         this.initPageX = p[0] - dx;
19304         this.initPageY = p[1] - dy;
19305
19306         this.lastPageX = p[0];
19307         this.lastPageY = p[1];
19308
19309
19310         this.setStartPosition(p);
19311     },
19312
19313     /**
19314      * Sets the start position of the element.  This is set when the obj
19315      * is initialized, the reset when a drag is started.
19316      * @method setStartPosition
19317      * @param pos current position (from previous lookup)
19318      * @private
19319      */
19320     setStartPosition: function(pos) {
19321         var p = pos || Dom.getXY( this.getEl() );
19322         this.deltaSetXY = null;
19323
19324         this.startPageX = p[0];
19325         this.startPageY = p[1];
19326     },
19327
19328     /**
19329      * Add this instance to a group of related drag/drop objects.  All
19330      * instances belong to at least one group, and can belong to as many
19331      * groups as needed.
19332      * @method addToGroup
19333      * @param sGroup {string} the name of the group
19334      */
19335     addToGroup: function(sGroup) {
19336         this.groups[sGroup] = true;
19337         this.DDM.regDragDrop(this, sGroup);
19338     },
19339
19340     /**
19341      * Remove's this instance from the supplied interaction group
19342      * @method removeFromGroup
19343      * @param {string}  sGroup  The group to drop
19344      */
19345     removeFromGroup: function(sGroup) {
19346         if (this.groups[sGroup]) {
19347             delete this.groups[sGroup];
19348         }
19349
19350         this.DDM.removeDDFromGroup(this, sGroup);
19351     },
19352
19353     /**
19354      * Allows you to specify that an element other than the linked element
19355      * will be moved with the cursor during a drag
19356      * @method setDragElId
19357      * @param id {string} the id of the element that will be used to initiate the drag
19358      */
19359     setDragElId: function(id) {
19360         this.dragElId = id;
19361     },
19362
19363     /**
19364      * Allows you to specify a child of the linked element that should be
19365      * used to initiate the drag operation.  An example of this would be if
19366      * you have a content div with text and links.  Clicking anywhere in the
19367      * content area would normally start the drag operation.  Use this method
19368      * to specify that an element inside of the content div is the element
19369      * that starts the drag operation.
19370      * @method setHandleElId
19371      * @param id {string} the id of the element that will be used to
19372      * initiate the drag.
19373      */
19374     setHandleElId: function(id) {
19375         if (typeof id !== "string") {
19376             id = Roo.id(id);
19377         }
19378         this.handleElId = id;
19379         this.DDM.regHandle(this.id, id);
19380     },
19381
19382     /**
19383      * Allows you to set an element outside of the linked element as a drag
19384      * handle
19385      * @method setOuterHandleElId
19386      * @param id the id of the element that will be used to initiate the drag
19387      */
19388     setOuterHandleElId: function(id) {
19389         if (typeof id !== "string") {
19390             id = Roo.id(id);
19391         }
19392         Event.on(id, "mousedown",
19393                 this.handleMouseDown, this);
19394         this.setHandleElId(id);
19395
19396         this.hasOuterHandles = true;
19397     },
19398
19399     /**
19400      * Remove all drag and drop hooks for this element
19401      * @method unreg
19402      */
19403     unreg: function() {
19404         Event.un(this.id, "mousedown",
19405                 this.handleMouseDown);
19406         Event.un(this.id, "touchstart",
19407                 this.handleMouseDown);
19408         this._domRef = null;
19409         this.DDM._remove(this);
19410     },
19411
19412     destroy : function(){
19413         this.unreg();
19414     },
19415
19416     /**
19417      * Returns true if this instance is locked, or the drag drop mgr is locked
19418      * (meaning that all drag/drop is disabled on the page.)
19419      * @method isLocked
19420      * @return {boolean} true if this obj or all drag/drop is locked, else
19421      * false
19422      */
19423     isLocked: function() {
19424         return (this.DDM.isLocked() || this.locked);
19425     },
19426
19427     /**
19428      * Fired when this object is clicked
19429      * @method handleMouseDown
19430      * @param {Event} e
19431      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19432      * @private
19433      */
19434     handleMouseDown: function(e, oDD){
19435      
19436         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19437             //Roo.log('not touch/ button !=0');
19438             return;
19439         }
19440         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19441             return; // double touch..
19442         }
19443         
19444
19445         if (this.isLocked()) {
19446             //Roo.log('locked');
19447             return;
19448         }
19449
19450         this.DDM.refreshCache(this.groups);
19451 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19452         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19453         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
19454             //Roo.log('no outer handes or not over target');
19455                 // do nothing.
19456         } else {
19457 //            Roo.log('check validator');
19458             if (this.clickValidator(e)) {
19459 //                Roo.log('validate success');
19460                 // set the initial element position
19461                 this.setStartPosition();
19462
19463
19464                 this.b4MouseDown(e);
19465                 this.onMouseDown(e);
19466
19467                 this.DDM.handleMouseDown(e, this);
19468
19469                 this.DDM.stopEvent(e);
19470             } else {
19471
19472
19473             }
19474         }
19475     },
19476
19477     clickValidator: function(e) {
19478         var target = e.getTarget();
19479         return ( this.isValidHandleChild(target) &&
19480                     (this.id == this.handleElId ||
19481                         this.DDM.handleWasClicked(target, this.id)) );
19482     },
19483
19484     /**
19485      * Allows you to specify a tag name that should not start a drag operation
19486      * when clicked.  This is designed to facilitate embedding links within a
19487      * drag handle that do something other than start the drag.
19488      * @method addInvalidHandleType
19489      * @param {string} tagName the type of element to exclude
19490      */
19491     addInvalidHandleType: function(tagName) {
19492         var type = tagName.toUpperCase();
19493         this.invalidHandleTypes[type] = type;
19494     },
19495
19496     /**
19497      * Lets you to specify an element id for a child of a drag handle
19498      * that should not initiate a drag
19499      * @method addInvalidHandleId
19500      * @param {string} id the element id of the element you wish to ignore
19501      */
19502     addInvalidHandleId: function(id) {
19503         if (typeof id !== "string") {
19504             id = Roo.id(id);
19505         }
19506         this.invalidHandleIds[id] = id;
19507     },
19508
19509     /**
19510      * Lets you specify a css class of elements that will not initiate a drag
19511      * @method addInvalidHandleClass
19512      * @param {string} cssClass the class of the elements you wish to ignore
19513      */
19514     addInvalidHandleClass: function(cssClass) {
19515         this.invalidHandleClasses.push(cssClass);
19516     },
19517
19518     /**
19519      * Unsets an excluded tag name set by addInvalidHandleType
19520      * @method removeInvalidHandleType
19521      * @param {string} tagName the type of element to unexclude
19522      */
19523     removeInvalidHandleType: function(tagName) {
19524         var type = tagName.toUpperCase();
19525         // this.invalidHandleTypes[type] = null;
19526         delete this.invalidHandleTypes[type];
19527     },
19528
19529     /**
19530      * Unsets an invalid handle id
19531      * @method removeInvalidHandleId
19532      * @param {string} id the id of the element to re-enable
19533      */
19534     removeInvalidHandleId: function(id) {
19535         if (typeof id !== "string") {
19536             id = Roo.id(id);
19537         }
19538         delete this.invalidHandleIds[id];
19539     },
19540
19541     /**
19542      * Unsets an invalid css class
19543      * @method removeInvalidHandleClass
19544      * @param {string} cssClass the class of the element(s) you wish to
19545      * re-enable
19546      */
19547     removeInvalidHandleClass: function(cssClass) {
19548         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19549             if (this.invalidHandleClasses[i] == cssClass) {
19550                 delete this.invalidHandleClasses[i];
19551             }
19552         }
19553     },
19554
19555     /**
19556      * Checks the tag exclusion list to see if this click should be ignored
19557      * @method isValidHandleChild
19558      * @param {HTMLElement} node the HTMLElement to evaluate
19559      * @return {boolean} true if this is a valid tag type, false if not
19560      */
19561     isValidHandleChild: function(node) {
19562
19563         var valid = true;
19564         // var n = (node.nodeName == "#text") ? node.parentNode : node;
19565         var nodeName;
19566         try {
19567             nodeName = node.nodeName.toUpperCase();
19568         } catch(e) {
19569             nodeName = node.nodeName;
19570         }
19571         valid = valid && !this.invalidHandleTypes[nodeName];
19572         valid = valid && !this.invalidHandleIds[node.id];
19573
19574         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19575             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19576         }
19577
19578
19579         return valid;
19580
19581     },
19582
19583     /**
19584      * Create the array of horizontal tick marks if an interval was specified
19585      * in setXConstraint().
19586      * @method setXTicks
19587      * @private
19588      */
19589     setXTicks: function(iStartX, iTickSize) {
19590         this.xTicks = [];
19591         this.xTickSize = iTickSize;
19592
19593         var tickMap = {};
19594
19595         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19596             if (!tickMap[i]) {
19597                 this.xTicks[this.xTicks.length] = i;
19598                 tickMap[i] = true;
19599             }
19600         }
19601
19602         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19603             if (!tickMap[i]) {
19604                 this.xTicks[this.xTicks.length] = i;
19605                 tickMap[i] = true;
19606             }
19607         }
19608
19609         this.xTicks.sort(this.DDM.numericSort) ;
19610     },
19611
19612     /**
19613      * Create the array of vertical tick marks if an interval was specified in
19614      * setYConstraint().
19615      * @method setYTicks
19616      * @private
19617      */
19618     setYTicks: function(iStartY, iTickSize) {
19619         this.yTicks = [];
19620         this.yTickSize = iTickSize;
19621
19622         var tickMap = {};
19623
19624         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19625             if (!tickMap[i]) {
19626                 this.yTicks[this.yTicks.length] = i;
19627                 tickMap[i] = true;
19628             }
19629         }
19630
19631         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19632             if (!tickMap[i]) {
19633                 this.yTicks[this.yTicks.length] = i;
19634                 tickMap[i] = true;
19635             }
19636         }
19637
19638         this.yTicks.sort(this.DDM.numericSort) ;
19639     },
19640
19641     /**
19642      * By default, the element can be dragged any place on the screen.  Use
19643      * this method to limit the horizontal travel of the element.  Pass in
19644      * 0,0 for the parameters if you want to lock the drag to the y axis.
19645      * @method setXConstraint
19646      * @param {int} iLeft the number of pixels the element can move to the left
19647      * @param {int} iRight the number of pixels the element can move to the
19648      * right
19649      * @param {int} iTickSize optional parameter for specifying that the
19650      * element
19651      * should move iTickSize pixels at a time.
19652      */
19653     setXConstraint: function(iLeft, iRight, iTickSize) {
19654         this.leftConstraint = iLeft;
19655         this.rightConstraint = iRight;
19656
19657         this.minX = this.initPageX - iLeft;
19658         this.maxX = this.initPageX + iRight;
19659         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19660
19661         this.constrainX = true;
19662     },
19663
19664     /**
19665      * Clears any constraints applied to this instance.  Also clears ticks
19666      * since they can't exist independent of a constraint at this time.
19667      * @method clearConstraints
19668      */
19669     clearConstraints: function() {
19670         this.constrainX = false;
19671         this.constrainY = false;
19672         this.clearTicks();
19673     },
19674
19675     /**
19676      * Clears any tick interval defined for this instance
19677      * @method clearTicks
19678      */
19679     clearTicks: function() {
19680         this.xTicks = null;
19681         this.yTicks = null;
19682         this.xTickSize = 0;
19683         this.yTickSize = 0;
19684     },
19685
19686     /**
19687      * By default, the element can be dragged any place on the screen.  Set
19688      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19689      * parameters if you want to lock the drag to the x axis.
19690      * @method setYConstraint
19691      * @param {int} iUp the number of pixels the element can move up
19692      * @param {int} iDown the number of pixels the element can move down
19693      * @param {int} iTickSize optional parameter for specifying that the
19694      * element should move iTickSize pixels at a time.
19695      */
19696     setYConstraint: function(iUp, iDown, iTickSize) {
19697         this.topConstraint = iUp;
19698         this.bottomConstraint = iDown;
19699
19700         this.minY = this.initPageY - iUp;
19701         this.maxY = this.initPageY + iDown;
19702         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19703
19704         this.constrainY = true;
19705
19706     },
19707
19708     /**
19709      * resetConstraints must be called if you manually reposition a dd element.
19710      * @method resetConstraints
19711      * @param {boolean} maintainOffset
19712      */
19713     resetConstraints: function() {
19714
19715
19716         // Maintain offsets if necessary
19717         if (this.initPageX || this.initPageX === 0) {
19718             // figure out how much this thing has moved
19719             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19720             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19721
19722             this.setInitPosition(dx, dy);
19723
19724         // This is the first time we have detected the element's position
19725         } else {
19726             this.setInitPosition();
19727         }
19728
19729         if (this.constrainX) {
19730             this.setXConstraint( this.leftConstraint,
19731                                  this.rightConstraint,
19732                                  this.xTickSize        );
19733         }
19734
19735         if (this.constrainY) {
19736             this.setYConstraint( this.topConstraint,
19737                                  this.bottomConstraint,
19738                                  this.yTickSize         );
19739         }
19740     },
19741
19742     /**
19743      * Normally the drag element is moved pixel by pixel, but we can specify
19744      * that it move a number of pixels at a time.  This method resolves the
19745      * location when we have it set up like this.
19746      * @method getTick
19747      * @param {int} val where we want to place the object
19748      * @param {int[]} tickArray sorted array of valid points
19749      * @return {int} the closest tick
19750      * @private
19751      */
19752     getTick: function(val, tickArray) {
19753
19754         if (!tickArray) {
19755             // If tick interval is not defined, it is effectively 1 pixel,
19756             // so we return the value passed to us.
19757             return val;
19758         } else if (tickArray[0] >= val) {
19759             // The value is lower than the first tick, so we return the first
19760             // tick.
19761             return tickArray[0];
19762         } else {
19763             for (var i=0, len=tickArray.length; i<len; ++i) {
19764                 var next = i + 1;
19765                 if (tickArray[next] && tickArray[next] >= val) {
19766                     var diff1 = val - tickArray[i];
19767                     var diff2 = tickArray[next] - val;
19768                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19769                 }
19770             }
19771
19772             // The value is larger than the last tick, so we return the last
19773             // tick.
19774             return tickArray[tickArray.length - 1];
19775         }
19776     },
19777
19778     /**
19779      * toString method
19780      * @method toString
19781      * @return {string} string representation of the dd obj
19782      */
19783     toString: function() {
19784         return ("DragDrop " + this.id);
19785     }
19786
19787 });
19788
19789 })();
19790 /*
19791  * Based on:
19792  * Ext JS Library 1.1.1
19793  * Copyright(c) 2006-2007, Ext JS, LLC.
19794  *
19795  * Originally Released Under LGPL - original licence link has changed is not relivant.
19796  *
19797  * Fork - LGPL
19798  * <script type="text/javascript">
19799  */
19800
19801
19802 /**
19803  * The drag and drop utility provides a framework for building drag and drop
19804  * applications.  In addition to enabling drag and drop for specific elements,
19805  * the drag and drop elements are tracked by the manager class, and the
19806  * interactions between the various elements are tracked during the drag and
19807  * the implementing code is notified about these important moments.
19808  */
19809
19810 // Only load the library once.  Rewriting the manager class would orphan
19811 // existing drag and drop instances.
19812 if (!Roo.dd.DragDropMgr) {
19813
19814 /**
19815  * @class Roo.dd.DragDropMgr
19816  * DragDropMgr is a singleton that tracks the element interaction for
19817  * all DragDrop items in the window.  Generally, you will not call
19818  * this class directly, but it does have helper methods that could
19819  * be useful in your DragDrop implementations.
19820  * @singleton
19821  */
19822 Roo.dd.DragDropMgr = function() {
19823
19824     var Event = Roo.EventManager;
19825
19826     return {
19827
19828         /**
19829          * Two dimensional Array of registered DragDrop objects.  The first
19830          * dimension is the DragDrop item group, the second the DragDrop
19831          * object.
19832          * @property ids
19833          * @type {string: string}
19834          * @private
19835          * @static
19836          */
19837         ids: {},
19838
19839         /**
19840          * Array of element ids defined as drag handles.  Used to determine
19841          * if the element that generated the mousedown event is actually the
19842          * handle and not the html element itself.
19843          * @property handleIds
19844          * @type {string: string}
19845          * @private
19846          * @static
19847          */
19848         handleIds: {},
19849
19850         /**
19851          * the DragDrop object that is currently being dragged
19852          * @property dragCurrent
19853          * @type DragDrop
19854          * @private
19855          * @static
19856          **/
19857         dragCurrent: null,
19858
19859         /**
19860          * the DragDrop object(s) that are being hovered over
19861          * @property dragOvers
19862          * @type Array
19863          * @private
19864          * @static
19865          */
19866         dragOvers: {},
19867
19868         /**
19869          * the X distance between the cursor and the object being dragged
19870          * @property deltaX
19871          * @type int
19872          * @private
19873          * @static
19874          */
19875         deltaX: 0,
19876
19877         /**
19878          * the Y distance between the cursor and the object being dragged
19879          * @property deltaY
19880          * @type int
19881          * @private
19882          * @static
19883          */
19884         deltaY: 0,
19885
19886         /**
19887          * Flag to determine if we should prevent the default behavior of the
19888          * events we define. By default this is true, but this can be set to
19889          * false if you need the default behavior (not recommended)
19890          * @property preventDefault
19891          * @type boolean
19892          * @static
19893          */
19894         preventDefault: true,
19895
19896         /**
19897          * Flag to determine if we should stop the propagation of the events
19898          * we generate. This is true by default but you may want to set it to
19899          * false if the html element contains other features that require the
19900          * mouse click.
19901          * @property stopPropagation
19902          * @type boolean
19903          * @static
19904          */
19905         stopPropagation: true,
19906
19907         /**
19908          * Internal flag that is set to true when drag and drop has been
19909          * intialized
19910          * @property initialized
19911          * @private
19912          * @static
19913          */
19914         initalized: false,
19915
19916         /**
19917          * All drag and drop can be disabled.
19918          * @property locked
19919          * @private
19920          * @static
19921          */
19922         locked: false,
19923
19924         /**
19925          * Called the first time an element is registered.
19926          * @method init
19927          * @private
19928          * @static
19929          */
19930         init: function() {
19931             this.initialized = true;
19932         },
19933
19934         /**
19935          * In point mode, drag and drop interaction is defined by the
19936          * location of the cursor during the drag/drop
19937          * @property POINT
19938          * @type int
19939          * @static
19940          */
19941         POINT: 0,
19942
19943         /**
19944          * In intersect mode, drag and drop interactio nis defined by the
19945          * overlap of two or more drag and drop objects.
19946          * @property INTERSECT
19947          * @type int
19948          * @static
19949          */
19950         INTERSECT: 1,
19951
19952         /**
19953          * The current drag and drop mode.  Default: POINT
19954          * @property mode
19955          * @type int
19956          * @static
19957          */
19958         mode: 0,
19959
19960         /**
19961          * Runs method on all drag and drop objects
19962          * @method _execOnAll
19963          * @private
19964          * @static
19965          */
19966         _execOnAll: function(sMethod, args) {
19967             for (var i in this.ids) {
19968                 for (var j in this.ids[i]) {
19969                     var oDD = this.ids[i][j];
19970                     if (! this.isTypeOfDD(oDD)) {
19971                         continue;
19972                     }
19973                     oDD[sMethod].apply(oDD, args);
19974                 }
19975             }
19976         },
19977
19978         /**
19979          * Drag and drop initialization.  Sets up the global event handlers
19980          * @method _onLoad
19981          * @private
19982          * @static
19983          */
19984         _onLoad: function() {
19985
19986             this.init();
19987
19988             if (!Roo.isTouch) {
19989                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19990                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19991             }
19992             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19993             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19994             
19995             Event.on(window,   "unload",    this._onUnload, this, true);
19996             Event.on(window,   "resize",    this._onResize, this, true);
19997             // Event.on(window,   "mouseout",    this._test);
19998
19999         },
20000
20001         /**
20002          * Reset constraints on all drag and drop objs
20003          * @method _onResize
20004          * @private
20005          * @static
20006          */
20007         _onResize: function(e) {
20008             this._execOnAll("resetConstraints", []);
20009         },
20010
20011         /**
20012          * Lock all drag and drop functionality
20013          * @method lock
20014          * @static
20015          */
20016         lock: function() { this.locked = true; },
20017
20018         /**
20019          * Unlock all drag and drop functionality
20020          * @method unlock
20021          * @static
20022          */
20023         unlock: function() { this.locked = false; },
20024
20025         /**
20026          * Is drag and drop locked?
20027          * @method isLocked
20028          * @return {boolean} True if drag and drop is locked, false otherwise.
20029          * @static
20030          */
20031         isLocked: function() { return this.locked; },
20032
20033         /**
20034          * Location cache that is set for all drag drop objects when a drag is
20035          * initiated, cleared when the drag is finished.
20036          * @property locationCache
20037          * @private
20038          * @static
20039          */
20040         locationCache: {},
20041
20042         /**
20043          * Set useCache to false if you want to force object the lookup of each
20044          * drag and drop linked element constantly during a drag.
20045          * @property useCache
20046          * @type boolean
20047          * @static
20048          */
20049         useCache: true,
20050
20051         /**
20052          * The number of pixels that the mouse needs to move after the
20053          * mousedown before the drag is initiated.  Default=3;
20054          * @property clickPixelThresh
20055          * @type int
20056          * @static
20057          */
20058         clickPixelThresh: 3,
20059
20060         /**
20061          * The number of milliseconds after the mousedown event to initiate the
20062          * drag if we don't get a mouseup event. Default=1000
20063          * @property clickTimeThresh
20064          * @type int
20065          * @static
20066          */
20067         clickTimeThresh: 350,
20068
20069         /**
20070          * Flag that indicates that either the drag pixel threshold or the
20071          * mousdown time threshold has been met
20072          * @property dragThreshMet
20073          * @type boolean
20074          * @private
20075          * @static
20076          */
20077         dragThreshMet: false,
20078
20079         /**
20080          * Timeout used for the click time threshold
20081          * @property clickTimeout
20082          * @type Object
20083          * @private
20084          * @static
20085          */
20086         clickTimeout: null,
20087
20088         /**
20089          * The X position of the mousedown event stored for later use when a
20090          * drag threshold is met.
20091          * @property startX
20092          * @type int
20093          * @private
20094          * @static
20095          */
20096         startX: 0,
20097
20098         /**
20099          * The Y position of the mousedown event stored for later use when a
20100          * drag threshold is met.
20101          * @property startY
20102          * @type int
20103          * @private
20104          * @static
20105          */
20106         startY: 0,
20107
20108         /**
20109          * Each DragDrop instance must be registered with the DragDropMgr.
20110          * This is executed in DragDrop.init()
20111          * @method regDragDrop
20112          * @param {DragDrop} oDD the DragDrop object to register
20113          * @param {String} sGroup the name of the group this element belongs to
20114          * @static
20115          */
20116         regDragDrop: function(oDD, sGroup) {
20117             if (!this.initialized) { this.init(); }
20118
20119             if (!this.ids[sGroup]) {
20120                 this.ids[sGroup] = {};
20121             }
20122             this.ids[sGroup][oDD.id] = oDD;
20123         },
20124
20125         /**
20126          * Removes the supplied dd instance from the supplied group. Executed
20127          * by DragDrop.removeFromGroup, so don't call this function directly.
20128          * @method removeDDFromGroup
20129          * @private
20130          * @static
20131          */
20132         removeDDFromGroup: function(oDD, sGroup) {
20133             if (!this.ids[sGroup]) {
20134                 this.ids[sGroup] = {};
20135             }
20136
20137             var obj = this.ids[sGroup];
20138             if (obj && obj[oDD.id]) {
20139                 delete obj[oDD.id];
20140             }
20141         },
20142
20143         /**
20144          * Unregisters a drag and drop item.  This is executed in
20145          * DragDrop.unreg, use that method instead of calling this directly.
20146          * @method _remove
20147          * @private
20148          * @static
20149          */
20150         _remove: function(oDD) {
20151             for (var g in oDD.groups) {
20152                 if (g && this.ids[g][oDD.id]) {
20153                     delete this.ids[g][oDD.id];
20154                 }
20155             }
20156             delete this.handleIds[oDD.id];
20157         },
20158
20159         /**
20160          * Each DragDrop handle element must be registered.  This is done
20161          * automatically when executing DragDrop.setHandleElId()
20162          * @method regHandle
20163          * @param {String} sDDId the DragDrop id this element is a handle for
20164          * @param {String} sHandleId the id of the element that is the drag
20165          * handle
20166          * @static
20167          */
20168         regHandle: function(sDDId, sHandleId) {
20169             if (!this.handleIds[sDDId]) {
20170                 this.handleIds[sDDId] = {};
20171             }
20172             this.handleIds[sDDId][sHandleId] = sHandleId;
20173         },
20174
20175         /**
20176          * Utility function to determine if a given element has been
20177          * registered as a drag drop item.
20178          * @method isDragDrop
20179          * @param {String} id the element id to check
20180          * @return {boolean} true if this element is a DragDrop item,
20181          * false otherwise
20182          * @static
20183          */
20184         isDragDrop: function(id) {
20185             return ( this.getDDById(id) ) ? true : false;
20186         },
20187
20188         /**
20189          * Returns the drag and drop instances that are in all groups the
20190          * passed in instance belongs to.
20191          * @method getRelated
20192          * @param {DragDrop} p_oDD the obj to get related data for
20193          * @param {boolean} bTargetsOnly if true, only return targetable objs
20194          * @return {DragDrop[]} the related instances
20195          * @static
20196          */
20197         getRelated: function(p_oDD, bTargetsOnly) {
20198             var oDDs = [];
20199             for (var i in p_oDD.groups) {
20200                 for (j in this.ids[i]) {
20201                     var dd = this.ids[i][j];
20202                     if (! this.isTypeOfDD(dd)) {
20203                         continue;
20204                     }
20205                     if (!bTargetsOnly || dd.isTarget) {
20206                         oDDs[oDDs.length] = dd;
20207                     }
20208                 }
20209             }
20210
20211             return oDDs;
20212         },
20213
20214         /**
20215          * Returns true if the specified dd target is a legal target for
20216          * the specifice drag obj
20217          * @method isLegalTarget
20218          * @param {DragDrop} the drag obj
20219          * @param {DragDrop} the target
20220          * @return {boolean} true if the target is a legal target for the
20221          * dd obj
20222          * @static
20223          */
20224         isLegalTarget: function (oDD, oTargetDD) {
20225             var targets = this.getRelated(oDD, true);
20226             for (var i=0, len=targets.length;i<len;++i) {
20227                 if (targets[i].id == oTargetDD.id) {
20228                     return true;
20229                 }
20230             }
20231
20232             return false;
20233         },
20234
20235         /**
20236          * My goal is to be able to transparently determine if an object is
20237          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
20238          * returns "object", oDD.constructor.toString() always returns
20239          * "DragDrop" and not the name of the subclass.  So for now it just
20240          * evaluates a well-known variable in DragDrop.
20241          * @method isTypeOfDD
20242          * @param {Object} the object to evaluate
20243          * @return {boolean} true if typeof oDD = DragDrop
20244          * @static
20245          */
20246         isTypeOfDD: function (oDD) {
20247             return (oDD && oDD.__ygDragDrop);
20248         },
20249
20250         /**
20251          * Utility function to determine if a given element has been
20252          * registered as a drag drop handle for the given Drag Drop object.
20253          * @method isHandle
20254          * @param {String} id the element id to check
20255          * @return {boolean} true if this element is a DragDrop handle, false
20256          * otherwise
20257          * @static
20258          */
20259         isHandle: function(sDDId, sHandleId) {
20260             return ( this.handleIds[sDDId] &&
20261                             this.handleIds[sDDId][sHandleId] );
20262         },
20263
20264         /**
20265          * Returns the DragDrop instance for a given id
20266          * @method getDDById
20267          * @param {String} id the id of the DragDrop object
20268          * @return {DragDrop} the drag drop object, null if it is not found
20269          * @static
20270          */
20271         getDDById: function(id) {
20272             for (var i in this.ids) {
20273                 if (this.ids[i][id]) {
20274                     return this.ids[i][id];
20275                 }
20276             }
20277             return null;
20278         },
20279
20280         /**
20281          * Fired after a registered DragDrop object gets the mousedown event.
20282          * Sets up the events required to track the object being dragged
20283          * @method handleMouseDown
20284          * @param {Event} e the event
20285          * @param oDD the DragDrop object being dragged
20286          * @private
20287          * @static
20288          */
20289         handleMouseDown: function(e, oDD) {
20290             if(Roo.QuickTips){
20291                 Roo.QuickTips.disable();
20292             }
20293             this.currentTarget = e.getTarget();
20294
20295             this.dragCurrent = oDD;
20296
20297             var el = oDD.getEl();
20298
20299             // track start position
20300             this.startX = e.getPageX();
20301             this.startY = e.getPageY();
20302
20303             this.deltaX = this.startX - el.offsetLeft;
20304             this.deltaY = this.startY - el.offsetTop;
20305
20306             this.dragThreshMet = false;
20307
20308             this.clickTimeout = setTimeout(
20309                     function() {
20310                         var DDM = Roo.dd.DDM;
20311                         DDM.startDrag(DDM.startX, DDM.startY);
20312                     },
20313                     this.clickTimeThresh );
20314         },
20315
20316         /**
20317          * Fired when either the drag pixel threshol or the mousedown hold
20318          * time threshold has been met.
20319          * @method startDrag
20320          * @param x {int} the X position of the original mousedown
20321          * @param y {int} the Y position of the original mousedown
20322          * @static
20323          */
20324         startDrag: function(x, y) {
20325             clearTimeout(this.clickTimeout);
20326             if (this.dragCurrent) {
20327                 this.dragCurrent.b4StartDrag(x, y);
20328                 this.dragCurrent.startDrag(x, y);
20329             }
20330             this.dragThreshMet = true;
20331         },
20332
20333         /**
20334          * Internal function to handle the mouseup event.  Will be invoked
20335          * from the context of the document.
20336          * @method handleMouseUp
20337          * @param {Event} e the event
20338          * @private
20339          * @static
20340          */
20341         handleMouseUp: function(e) {
20342
20343             if(Roo.QuickTips){
20344                 Roo.QuickTips.enable();
20345             }
20346             if (! this.dragCurrent) {
20347                 return;
20348             }
20349
20350             clearTimeout(this.clickTimeout);
20351
20352             if (this.dragThreshMet) {
20353                 this.fireEvents(e, true);
20354             } else {
20355             }
20356
20357             this.stopDrag(e);
20358
20359             this.stopEvent(e);
20360         },
20361
20362         /**
20363          * Utility to stop event propagation and event default, if these
20364          * features are turned on.
20365          * @method stopEvent
20366          * @param {Event} e the event as returned by this.getEvent()
20367          * @static
20368          */
20369         stopEvent: function(e){
20370             if(this.stopPropagation) {
20371                 e.stopPropagation();
20372             }
20373
20374             if (this.preventDefault) {
20375                 e.preventDefault();
20376             }
20377         },
20378
20379         /**
20380          * Internal function to clean up event handlers after the drag
20381          * operation is complete
20382          * @method stopDrag
20383          * @param {Event} e the event
20384          * @private
20385          * @static
20386          */
20387         stopDrag: function(e) {
20388             // Fire the drag end event for the item that was dragged
20389             if (this.dragCurrent) {
20390                 if (this.dragThreshMet) {
20391                     this.dragCurrent.b4EndDrag(e);
20392                     this.dragCurrent.endDrag(e);
20393                 }
20394
20395                 this.dragCurrent.onMouseUp(e);
20396             }
20397
20398             this.dragCurrent = null;
20399             this.dragOvers = {};
20400         },
20401
20402         /**
20403          * Internal function to handle the mousemove event.  Will be invoked
20404          * from the context of the html element.
20405          *
20406          * @TODO figure out what we can do about mouse events lost when the
20407          * user drags objects beyond the window boundary.  Currently we can
20408          * detect this in internet explorer by verifying that the mouse is
20409          * down during the mousemove event.  Firefox doesn't give us the
20410          * button state on the mousemove event.
20411          * @method handleMouseMove
20412          * @param {Event} e the event
20413          * @private
20414          * @static
20415          */
20416         handleMouseMove: function(e) {
20417             if (! this.dragCurrent) {
20418                 return true;
20419             }
20420
20421             // var button = e.which || e.button;
20422
20423             // check for IE mouseup outside of page boundary
20424             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20425                 this.stopEvent(e);
20426                 return this.handleMouseUp(e);
20427             }
20428
20429             if (!this.dragThreshMet) {
20430                 var diffX = Math.abs(this.startX - e.getPageX());
20431                 var diffY = Math.abs(this.startY - e.getPageY());
20432                 if (diffX > this.clickPixelThresh ||
20433                             diffY > this.clickPixelThresh) {
20434                     this.startDrag(this.startX, this.startY);
20435                 }
20436             }
20437
20438             if (this.dragThreshMet) {
20439                 this.dragCurrent.b4Drag(e);
20440                 this.dragCurrent.onDrag(e);
20441                 if(!this.dragCurrent.moveOnly){
20442                     this.fireEvents(e, false);
20443                 }
20444             }
20445
20446             this.stopEvent(e);
20447
20448             return true;
20449         },
20450
20451         /**
20452          * Iterates over all of the DragDrop elements to find ones we are
20453          * hovering over or dropping on
20454          * @method fireEvents
20455          * @param {Event} e the event
20456          * @param {boolean} isDrop is this a drop op or a mouseover op?
20457          * @private
20458          * @static
20459          */
20460         fireEvents: function(e, isDrop) {
20461             var dc = this.dragCurrent;
20462
20463             // If the user did the mouse up outside of the window, we could
20464             // get here even though we have ended the drag.
20465             if (!dc || dc.isLocked()) {
20466                 return;
20467             }
20468
20469             var pt = e.getPoint();
20470
20471             // cache the previous dragOver array
20472             var oldOvers = [];
20473
20474             var outEvts   = [];
20475             var overEvts  = [];
20476             var dropEvts  = [];
20477             var enterEvts = [];
20478
20479             // Check to see if the object(s) we were hovering over is no longer
20480             // being hovered over so we can fire the onDragOut event
20481             for (var i in this.dragOvers) {
20482
20483                 var ddo = this.dragOvers[i];
20484
20485                 if (! this.isTypeOfDD(ddo)) {
20486                     continue;
20487                 }
20488
20489                 if (! this.isOverTarget(pt, ddo, this.mode)) {
20490                     outEvts.push( ddo );
20491                 }
20492
20493                 oldOvers[i] = true;
20494                 delete this.dragOvers[i];
20495             }
20496
20497             for (var sGroup in dc.groups) {
20498
20499                 if ("string" != typeof sGroup) {
20500                     continue;
20501                 }
20502
20503                 for (i in this.ids[sGroup]) {
20504                     var oDD = this.ids[sGroup][i];
20505                     if (! this.isTypeOfDD(oDD)) {
20506                         continue;
20507                     }
20508
20509                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20510                         if (this.isOverTarget(pt, oDD, this.mode)) {
20511                             // look for drop interactions
20512                             if (isDrop) {
20513                                 dropEvts.push( oDD );
20514                             // look for drag enter and drag over interactions
20515                             } else {
20516
20517                                 // initial drag over: dragEnter fires
20518                                 if (!oldOvers[oDD.id]) {
20519                                     enterEvts.push( oDD );
20520                                 // subsequent drag overs: dragOver fires
20521                                 } else {
20522                                     overEvts.push( oDD );
20523                                 }
20524
20525                                 this.dragOvers[oDD.id] = oDD;
20526                             }
20527                         }
20528                     }
20529                 }
20530             }
20531
20532             if (this.mode) {
20533                 if (outEvts.length) {
20534                     dc.b4DragOut(e, outEvts);
20535                     dc.onDragOut(e, outEvts);
20536                 }
20537
20538                 if (enterEvts.length) {
20539                     dc.onDragEnter(e, enterEvts);
20540                 }
20541
20542                 if (overEvts.length) {
20543                     dc.b4DragOver(e, overEvts);
20544                     dc.onDragOver(e, overEvts);
20545                 }
20546
20547                 if (dropEvts.length) {
20548                     dc.b4DragDrop(e, dropEvts);
20549                     dc.onDragDrop(e, dropEvts);
20550                 }
20551
20552             } else {
20553                 // fire dragout events
20554                 var len = 0;
20555                 for (i=0, len=outEvts.length; i<len; ++i) {
20556                     dc.b4DragOut(e, outEvts[i].id);
20557                     dc.onDragOut(e, outEvts[i].id);
20558                 }
20559
20560                 // fire enter events
20561                 for (i=0,len=enterEvts.length; i<len; ++i) {
20562                     // dc.b4DragEnter(e, oDD.id);
20563                     dc.onDragEnter(e, enterEvts[i].id);
20564                 }
20565
20566                 // fire over events
20567                 for (i=0,len=overEvts.length; i<len; ++i) {
20568                     dc.b4DragOver(e, overEvts[i].id);
20569                     dc.onDragOver(e, overEvts[i].id);
20570                 }
20571
20572                 // fire drop events
20573                 for (i=0, len=dropEvts.length; i<len; ++i) {
20574                     dc.b4DragDrop(e, dropEvts[i].id);
20575                     dc.onDragDrop(e, dropEvts[i].id);
20576                 }
20577
20578             }
20579
20580             // notify about a drop that did not find a target
20581             if (isDrop && !dropEvts.length) {
20582                 dc.onInvalidDrop(e);
20583             }
20584
20585         },
20586
20587         /**
20588          * Helper function for getting the best match from the list of drag
20589          * and drop objects returned by the drag and drop events when we are
20590          * in INTERSECT mode.  It returns either the first object that the
20591          * cursor is over, or the object that has the greatest overlap with
20592          * the dragged element.
20593          * @method getBestMatch
20594          * @param  {DragDrop[]} dds The array of drag and drop objects
20595          * targeted
20596          * @return {DragDrop}       The best single match
20597          * @static
20598          */
20599         getBestMatch: function(dds) {
20600             var winner = null;
20601             // Return null if the input is not what we expect
20602             //if (!dds || !dds.length || dds.length == 0) {
20603                // winner = null;
20604             // If there is only one item, it wins
20605             //} else if (dds.length == 1) {
20606
20607             var len = dds.length;
20608
20609             if (len == 1) {
20610                 winner = dds[0];
20611             } else {
20612                 // Loop through the targeted items
20613                 for (var i=0; i<len; ++i) {
20614                     var dd = dds[i];
20615                     // If the cursor is over the object, it wins.  If the
20616                     // cursor is over multiple matches, the first one we come
20617                     // to wins.
20618                     if (dd.cursorIsOver) {
20619                         winner = dd;
20620                         break;
20621                     // Otherwise the object with the most overlap wins
20622                     } else {
20623                         if (!winner ||
20624                             winner.overlap.getArea() < dd.overlap.getArea()) {
20625                             winner = dd;
20626                         }
20627                     }
20628                 }
20629             }
20630
20631             return winner;
20632         },
20633
20634         /**
20635          * Refreshes the cache of the top-left and bottom-right points of the
20636          * drag and drop objects in the specified group(s).  This is in the
20637          * format that is stored in the drag and drop instance, so typical
20638          * usage is:
20639          * <code>
20640          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20641          * </code>
20642          * Alternatively:
20643          * <code>
20644          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20645          * </code>
20646          * @TODO this really should be an indexed array.  Alternatively this
20647          * method could accept both.
20648          * @method refreshCache
20649          * @param {Object} groups an associative array of groups to refresh
20650          * @static
20651          */
20652         refreshCache: function(groups) {
20653             for (var sGroup in groups) {
20654                 if ("string" != typeof sGroup) {
20655                     continue;
20656                 }
20657                 for (var i in this.ids[sGroup]) {
20658                     var oDD = this.ids[sGroup][i];
20659
20660                     if (this.isTypeOfDD(oDD)) {
20661                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20662                         var loc = this.getLocation(oDD);
20663                         if (loc) {
20664                             this.locationCache[oDD.id] = loc;
20665                         } else {
20666                             delete this.locationCache[oDD.id];
20667                             // this will unregister the drag and drop object if
20668                             // the element is not in a usable state
20669                             // oDD.unreg();
20670                         }
20671                     }
20672                 }
20673             }
20674         },
20675
20676         /**
20677          * This checks to make sure an element exists and is in the DOM.  The
20678          * main purpose is to handle cases where innerHTML is used to remove
20679          * drag and drop objects from the DOM.  IE provides an 'unspecified
20680          * error' when trying to access the offsetParent of such an element
20681          * @method verifyEl
20682          * @param {HTMLElement} el the element to check
20683          * @return {boolean} true if the element looks usable
20684          * @static
20685          */
20686         verifyEl: function(el) {
20687             if (el) {
20688                 var parent;
20689                 if(Roo.isIE){
20690                     try{
20691                         parent = el.offsetParent;
20692                     }catch(e){}
20693                 }else{
20694                     parent = el.offsetParent;
20695                 }
20696                 if (parent) {
20697                     return true;
20698                 }
20699             }
20700
20701             return false;
20702         },
20703
20704         /**
20705          * Returns a Region object containing the drag and drop element's position
20706          * and size, including the padding configured for it
20707          * @method getLocation
20708          * @param {DragDrop} oDD the drag and drop object to get the
20709          *                       location for
20710          * @return {Roo.lib.Region} a Region object representing the total area
20711          *                             the element occupies, including any padding
20712          *                             the instance is configured for.
20713          * @static
20714          */
20715         getLocation: function(oDD) {
20716             if (! this.isTypeOfDD(oDD)) {
20717                 return null;
20718             }
20719
20720             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20721
20722             try {
20723                 pos= Roo.lib.Dom.getXY(el);
20724             } catch (e) { }
20725
20726             if (!pos) {
20727                 return null;
20728             }
20729
20730             x1 = pos[0];
20731             x2 = x1 + el.offsetWidth;
20732             y1 = pos[1];
20733             y2 = y1 + el.offsetHeight;
20734
20735             t = y1 - oDD.padding[0];
20736             r = x2 + oDD.padding[1];
20737             b = y2 + oDD.padding[2];
20738             l = x1 - oDD.padding[3];
20739
20740             return new Roo.lib.Region( t, r, b, l );
20741         },
20742
20743         /**
20744          * Checks the cursor location to see if it over the target
20745          * @method isOverTarget
20746          * @param {Roo.lib.Point} pt The point to evaluate
20747          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20748          * @return {boolean} true if the mouse is over the target
20749          * @private
20750          * @static
20751          */
20752         isOverTarget: function(pt, oTarget, intersect) {
20753             // use cache if available
20754             var loc = this.locationCache[oTarget.id];
20755             if (!loc || !this.useCache) {
20756                 loc = this.getLocation(oTarget);
20757                 this.locationCache[oTarget.id] = loc;
20758
20759             }
20760
20761             if (!loc) {
20762                 return false;
20763             }
20764
20765             oTarget.cursorIsOver = loc.contains( pt );
20766
20767             // DragDrop is using this as a sanity check for the initial mousedown
20768             // in this case we are done.  In POINT mode, if the drag obj has no
20769             // contraints, we are also done. Otherwise we need to evaluate the
20770             // location of the target as related to the actual location of the
20771             // dragged element.
20772             var dc = this.dragCurrent;
20773             if (!dc || !dc.getTargetCoord ||
20774                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20775                 return oTarget.cursorIsOver;
20776             }
20777
20778             oTarget.overlap = null;
20779
20780             // Get the current location of the drag element, this is the
20781             // location of the mouse event less the delta that represents
20782             // where the original mousedown happened on the element.  We
20783             // need to consider constraints and ticks as well.
20784             var pos = dc.getTargetCoord(pt.x, pt.y);
20785
20786             var el = dc.getDragEl();
20787             var curRegion = new Roo.lib.Region( pos.y,
20788                                                    pos.x + el.offsetWidth,
20789                                                    pos.y + el.offsetHeight,
20790                                                    pos.x );
20791
20792             var overlap = curRegion.intersect(loc);
20793
20794             if (overlap) {
20795                 oTarget.overlap = overlap;
20796                 return (intersect) ? true : oTarget.cursorIsOver;
20797             } else {
20798                 return false;
20799             }
20800         },
20801
20802         /**
20803          * unload event handler
20804          * @method _onUnload
20805          * @private
20806          * @static
20807          */
20808         _onUnload: function(e, me) {
20809             Roo.dd.DragDropMgr.unregAll();
20810         },
20811
20812         /**
20813          * Cleans up the drag and drop events and objects.
20814          * @method unregAll
20815          * @private
20816          * @static
20817          */
20818         unregAll: function() {
20819
20820             if (this.dragCurrent) {
20821                 this.stopDrag();
20822                 this.dragCurrent = null;
20823             }
20824
20825             this._execOnAll("unreg", []);
20826
20827             for (i in this.elementCache) {
20828                 delete this.elementCache[i];
20829             }
20830
20831             this.elementCache = {};
20832             this.ids = {};
20833         },
20834
20835         /**
20836          * A cache of DOM elements
20837          * @property elementCache
20838          * @private
20839          * @static
20840          */
20841         elementCache: {},
20842
20843         /**
20844          * Get the wrapper for the DOM element specified
20845          * @method getElWrapper
20846          * @param {String} id the id of the element to get
20847          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20848          * @private
20849          * @deprecated This wrapper isn't that useful
20850          * @static
20851          */
20852         getElWrapper: function(id) {
20853             var oWrapper = this.elementCache[id];
20854             if (!oWrapper || !oWrapper.el) {
20855                 oWrapper = this.elementCache[id] =
20856                     new this.ElementWrapper(Roo.getDom(id));
20857             }
20858             return oWrapper;
20859         },
20860
20861         /**
20862          * Returns the actual DOM element
20863          * @method getElement
20864          * @param {String} id the id of the elment to get
20865          * @return {Object} The element
20866          * @deprecated use Roo.getDom instead
20867          * @static
20868          */
20869         getElement: function(id) {
20870             return Roo.getDom(id);
20871         },
20872
20873         /**
20874          * Returns the style property for the DOM element (i.e.,
20875          * document.getElById(id).style)
20876          * @method getCss
20877          * @param {String} id the id of the elment to get
20878          * @return {Object} The style property of the element
20879          * @deprecated use Roo.getDom instead
20880          * @static
20881          */
20882         getCss: function(id) {
20883             var el = Roo.getDom(id);
20884             return (el) ? el.style : null;
20885         },
20886
20887         /**
20888          * Inner class for cached elements
20889          * @class DragDropMgr.ElementWrapper
20890          * @for DragDropMgr
20891          * @private
20892          * @deprecated
20893          */
20894         ElementWrapper: function(el) {
20895                 /**
20896                  * The element
20897                  * @property el
20898                  */
20899                 this.el = el || null;
20900                 /**
20901                  * The element id
20902                  * @property id
20903                  */
20904                 this.id = this.el && el.id;
20905                 /**
20906                  * A reference to the style property
20907                  * @property css
20908                  */
20909                 this.css = this.el && el.style;
20910             },
20911
20912         /**
20913          * Returns the X position of an html element
20914          * @method getPosX
20915          * @param el the element for which to get the position
20916          * @return {int} the X coordinate
20917          * @for DragDropMgr
20918          * @deprecated use Roo.lib.Dom.getX instead
20919          * @static
20920          */
20921         getPosX: function(el) {
20922             return Roo.lib.Dom.getX(el);
20923         },
20924
20925         /**
20926          * Returns the Y position of an html element
20927          * @method getPosY
20928          * @param el the element for which to get the position
20929          * @return {int} the Y coordinate
20930          * @deprecated use Roo.lib.Dom.getY instead
20931          * @static
20932          */
20933         getPosY: function(el) {
20934             return Roo.lib.Dom.getY(el);
20935         },
20936
20937         /**
20938          * Swap two nodes.  In IE, we use the native method, for others we
20939          * emulate the IE behavior
20940          * @method swapNode
20941          * @param n1 the first node to swap
20942          * @param n2 the other node to swap
20943          * @static
20944          */
20945         swapNode: function(n1, n2) {
20946             if (n1.swapNode) {
20947                 n1.swapNode(n2);
20948             } else {
20949                 var p = n2.parentNode;
20950                 var s = n2.nextSibling;
20951
20952                 if (s == n1) {
20953                     p.insertBefore(n1, n2);
20954                 } else if (n2 == n1.nextSibling) {
20955                     p.insertBefore(n2, n1);
20956                 } else {
20957                     n1.parentNode.replaceChild(n2, n1);
20958                     p.insertBefore(n1, s);
20959                 }
20960             }
20961         },
20962
20963         /**
20964          * Returns the current scroll position
20965          * @method getScroll
20966          * @private
20967          * @static
20968          */
20969         getScroll: function () {
20970             var t, l, dde=document.documentElement, db=document.body;
20971             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20972                 t = dde.scrollTop;
20973                 l = dde.scrollLeft;
20974             } else if (db) {
20975                 t = db.scrollTop;
20976                 l = db.scrollLeft;
20977             } else {
20978
20979             }
20980             return { top: t, left: l };
20981         },
20982
20983         /**
20984          * Returns the specified element style property
20985          * @method getStyle
20986          * @param {HTMLElement} el          the element
20987          * @param {string}      styleProp   the style property
20988          * @return {string} The value of the style property
20989          * @deprecated use Roo.lib.Dom.getStyle
20990          * @static
20991          */
20992         getStyle: function(el, styleProp) {
20993             return Roo.fly(el).getStyle(styleProp);
20994         },
20995
20996         /**
20997          * Gets the scrollTop
20998          * @method getScrollTop
20999          * @return {int} the document's scrollTop
21000          * @static
21001          */
21002         getScrollTop: function () { return this.getScroll().top; },
21003
21004         /**
21005          * Gets the scrollLeft
21006          * @method getScrollLeft
21007          * @return {int} the document's scrollTop
21008          * @static
21009          */
21010         getScrollLeft: function () { return this.getScroll().left; },
21011
21012         /**
21013          * Sets the x/y position of an element to the location of the
21014          * target element.
21015          * @method moveToEl
21016          * @param {HTMLElement} moveEl      The element to move
21017          * @param {HTMLElement} targetEl    The position reference element
21018          * @static
21019          */
21020         moveToEl: function (moveEl, targetEl) {
21021             var aCoord = Roo.lib.Dom.getXY(targetEl);
21022             Roo.lib.Dom.setXY(moveEl, aCoord);
21023         },
21024
21025         /**
21026          * Numeric array sort function
21027          * @method numericSort
21028          * @static
21029          */
21030         numericSort: function(a, b) { return (a - b); },
21031
21032         /**
21033          * Internal counter
21034          * @property _timeoutCount
21035          * @private
21036          * @static
21037          */
21038         _timeoutCount: 0,
21039
21040         /**
21041          * Trying to make the load order less important.  Without this we get
21042          * an error if this file is loaded before the Event Utility.
21043          * @method _addListeners
21044          * @private
21045          * @static
21046          */
21047         _addListeners: function() {
21048             var DDM = Roo.dd.DDM;
21049             if ( Roo.lib.Event && document ) {
21050                 DDM._onLoad();
21051             } else {
21052                 if (DDM._timeoutCount > 2000) {
21053                 } else {
21054                     setTimeout(DDM._addListeners, 10);
21055                     if (document && document.body) {
21056                         DDM._timeoutCount += 1;
21057                     }
21058                 }
21059             }
21060         },
21061
21062         /**
21063          * Recursively searches the immediate parent and all child nodes for
21064          * the handle element in order to determine wheter or not it was
21065          * clicked.
21066          * @method handleWasClicked
21067          * @param node the html element to inspect
21068          * @static
21069          */
21070         handleWasClicked: function(node, id) {
21071             if (this.isHandle(id, node.id)) {
21072                 return true;
21073             } else {
21074                 // check to see if this is a text node child of the one we want
21075                 var p = node.parentNode;
21076
21077                 while (p) {
21078                     if (this.isHandle(id, p.id)) {
21079                         return true;
21080                     } else {
21081                         p = p.parentNode;
21082                     }
21083                 }
21084             }
21085
21086             return false;
21087         }
21088
21089     };
21090
21091 }();
21092
21093 // shorter alias, save a few bytes
21094 Roo.dd.DDM = Roo.dd.DragDropMgr;
21095 Roo.dd.DDM._addListeners();
21096
21097 }/*
21098  * Based on:
21099  * Ext JS Library 1.1.1
21100  * Copyright(c) 2006-2007, Ext JS, LLC.
21101  *
21102  * Originally Released Under LGPL - original licence link has changed is not relivant.
21103  *
21104  * Fork - LGPL
21105  * <script type="text/javascript">
21106  */
21107
21108 /**
21109  * @class Roo.dd.DD
21110  * A DragDrop implementation where the linked element follows the
21111  * mouse cursor during a drag.
21112  * @extends Roo.dd.DragDrop
21113  * @constructor
21114  * @param {String} id the id of the linked element
21115  * @param {String} sGroup the group of related DragDrop items
21116  * @param {object} config an object containing configurable attributes
21117  *                Valid properties for DD:
21118  *                    scroll
21119  */
21120 Roo.dd.DD = function(id, sGroup, config) {
21121     if (id) {
21122         this.init(id, sGroup, config);
21123     }
21124 };
21125
21126 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21127
21128     /**
21129      * When set to true, the utility automatically tries to scroll the browser
21130      * window wehn a drag and drop element is dragged near the viewport boundary.
21131      * Defaults to true.
21132      * @property scroll
21133      * @type boolean
21134      */
21135     scroll: true,
21136
21137     /**
21138      * Sets the pointer offset to the distance between the linked element's top
21139      * left corner and the location the element was clicked
21140      * @method autoOffset
21141      * @param {int} iPageX the X coordinate of the click
21142      * @param {int} iPageY the Y coordinate of the click
21143      */
21144     autoOffset: function(iPageX, iPageY) {
21145         var x = iPageX - this.startPageX;
21146         var y = iPageY - this.startPageY;
21147         this.setDelta(x, y);
21148     },
21149
21150     /**
21151      * Sets the pointer offset.  You can call this directly to force the
21152      * offset to be in a particular location (e.g., pass in 0,0 to set it
21153      * to the center of the object)
21154      * @method setDelta
21155      * @param {int} iDeltaX the distance from the left
21156      * @param {int} iDeltaY the distance from the top
21157      */
21158     setDelta: function(iDeltaX, iDeltaY) {
21159         this.deltaX = iDeltaX;
21160         this.deltaY = iDeltaY;
21161     },
21162
21163     /**
21164      * Sets the drag element to the location of the mousedown or click event,
21165      * maintaining the cursor location relative to the location on the element
21166      * that was clicked.  Override this if you want to place the element in a
21167      * location other than where the cursor is.
21168      * @method setDragElPos
21169      * @param {int} iPageX the X coordinate of the mousedown or drag event
21170      * @param {int} iPageY the Y coordinate of the mousedown or drag event
21171      */
21172     setDragElPos: function(iPageX, iPageY) {
21173         // the first time we do this, we are going to check to make sure
21174         // the element has css positioning
21175
21176         var el = this.getDragEl();
21177         this.alignElWithMouse(el, iPageX, iPageY);
21178     },
21179
21180     /**
21181      * Sets the element to the location of the mousedown or click event,
21182      * maintaining the cursor location relative to the location on the element
21183      * that was clicked.  Override this if you want to place the element in a
21184      * location other than where the cursor is.
21185      * @method alignElWithMouse
21186      * @param {HTMLElement} el the element to move
21187      * @param {int} iPageX the X coordinate of the mousedown or drag event
21188      * @param {int} iPageY the Y coordinate of the mousedown or drag event
21189      */
21190     alignElWithMouse: function(el, iPageX, iPageY) {
21191         var oCoord = this.getTargetCoord(iPageX, iPageY);
21192         var fly = el.dom ? el : Roo.fly(el);
21193         if (!this.deltaSetXY) {
21194             var aCoord = [oCoord.x, oCoord.y];
21195             fly.setXY(aCoord);
21196             var newLeft = fly.getLeft(true);
21197             var newTop  = fly.getTop(true);
21198             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21199         } else {
21200             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21201         }
21202
21203         this.cachePosition(oCoord.x, oCoord.y);
21204         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21205         return oCoord;
21206     },
21207
21208     /**
21209      * Saves the most recent position so that we can reset the constraints and
21210      * tick marks on-demand.  We need to know this so that we can calculate the
21211      * number of pixels the element is offset from its original position.
21212      * @method cachePosition
21213      * @param iPageX the current x position (optional, this just makes it so we
21214      * don't have to look it up again)
21215      * @param iPageY the current y position (optional, this just makes it so we
21216      * don't have to look it up again)
21217      */
21218     cachePosition: function(iPageX, iPageY) {
21219         if (iPageX) {
21220             this.lastPageX = iPageX;
21221             this.lastPageY = iPageY;
21222         } else {
21223             var aCoord = Roo.lib.Dom.getXY(this.getEl());
21224             this.lastPageX = aCoord[0];
21225             this.lastPageY = aCoord[1];
21226         }
21227     },
21228
21229     /**
21230      * Auto-scroll the window if the dragged object has been moved beyond the
21231      * visible window boundary.
21232      * @method autoScroll
21233      * @param {int} x the drag element's x position
21234      * @param {int} y the drag element's y position
21235      * @param {int} h the height of the drag element
21236      * @param {int} w the width of the drag element
21237      * @private
21238      */
21239     autoScroll: function(x, y, h, w) {
21240
21241         if (this.scroll) {
21242             // The client height
21243             var clientH = Roo.lib.Dom.getViewWidth();
21244
21245             // The client width
21246             var clientW = Roo.lib.Dom.getViewHeight();
21247
21248             // The amt scrolled down
21249             var st = this.DDM.getScrollTop();
21250
21251             // The amt scrolled right
21252             var sl = this.DDM.getScrollLeft();
21253
21254             // Location of the bottom of the element
21255             var bot = h + y;
21256
21257             // Location of the right of the element
21258             var right = w + x;
21259
21260             // The distance from the cursor to the bottom of the visible area,
21261             // adjusted so that we don't scroll if the cursor is beyond the
21262             // element drag constraints
21263             var toBot = (clientH + st - y - this.deltaY);
21264
21265             // The distance from the cursor to the right of the visible area
21266             var toRight = (clientW + sl - x - this.deltaX);
21267
21268
21269             // How close to the edge the cursor must be before we scroll
21270             // var thresh = (document.all) ? 100 : 40;
21271             var thresh = 40;
21272
21273             // How many pixels to scroll per autoscroll op.  This helps to reduce
21274             // clunky scrolling. IE is more sensitive about this ... it needs this
21275             // value to be higher.
21276             var scrAmt = (document.all) ? 80 : 30;
21277
21278             // Scroll down if we are near the bottom of the visible page and the
21279             // obj extends below the crease
21280             if ( bot > clientH && toBot < thresh ) {
21281                 window.scrollTo(sl, st + scrAmt);
21282             }
21283
21284             // Scroll up if the window is scrolled down and the top of the object
21285             // goes above the top border
21286             if ( y < st && st > 0 && y - st < thresh ) {
21287                 window.scrollTo(sl, st - scrAmt);
21288             }
21289
21290             // Scroll right if the obj is beyond the right border and the cursor is
21291             // near the border.
21292             if ( right > clientW && toRight < thresh ) {
21293                 window.scrollTo(sl + scrAmt, st);
21294             }
21295
21296             // Scroll left if the window has been scrolled to the right and the obj
21297             // extends past the left border
21298             if ( x < sl && sl > 0 && x - sl < thresh ) {
21299                 window.scrollTo(sl - scrAmt, st);
21300             }
21301         }
21302     },
21303
21304     /**
21305      * Finds the location the element should be placed if we want to move
21306      * it to where the mouse location less the click offset would place us.
21307      * @method getTargetCoord
21308      * @param {int} iPageX the X coordinate of the click
21309      * @param {int} iPageY the Y coordinate of the click
21310      * @return an object that contains the coordinates (Object.x and Object.y)
21311      * @private
21312      */
21313     getTargetCoord: function(iPageX, iPageY) {
21314
21315
21316         var x = iPageX - this.deltaX;
21317         var y = iPageY - this.deltaY;
21318
21319         if (this.constrainX) {
21320             if (x < this.minX) { x = this.minX; }
21321             if (x > this.maxX) { x = this.maxX; }
21322         }
21323
21324         if (this.constrainY) {
21325             if (y < this.minY) { y = this.minY; }
21326             if (y > this.maxY) { y = this.maxY; }
21327         }
21328
21329         x = this.getTick(x, this.xTicks);
21330         y = this.getTick(y, this.yTicks);
21331
21332
21333         return {x:x, y:y};
21334     },
21335
21336     /*
21337      * Sets up config options specific to this class. Overrides
21338      * Roo.dd.DragDrop, but all versions of this method through the
21339      * inheritance chain are called
21340      */
21341     applyConfig: function() {
21342         Roo.dd.DD.superclass.applyConfig.call(this);
21343         this.scroll = (this.config.scroll !== false);
21344     },
21345
21346     /*
21347      * Event that fires prior to the onMouseDown event.  Overrides
21348      * Roo.dd.DragDrop.
21349      */
21350     b4MouseDown: function(e) {
21351         // this.resetConstraints();
21352         this.autoOffset(e.getPageX(),
21353                             e.getPageY());
21354     },
21355
21356     /*
21357      * Event that fires prior to the onDrag event.  Overrides
21358      * Roo.dd.DragDrop.
21359      */
21360     b4Drag: function(e) {
21361         this.setDragElPos(e.getPageX(),
21362                             e.getPageY());
21363     },
21364
21365     toString: function() {
21366         return ("DD " + this.id);
21367     }
21368
21369     //////////////////////////////////////////////////////////////////////////
21370     // Debugging ygDragDrop events that can be overridden
21371     //////////////////////////////////////////////////////////////////////////
21372     /*
21373     startDrag: function(x, y) {
21374     },
21375
21376     onDrag: function(e) {
21377     },
21378
21379     onDragEnter: function(e, id) {
21380     },
21381
21382     onDragOver: function(e, id) {
21383     },
21384
21385     onDragOut: function(e, id) {
21386     },
21387
21388     onDragDrop: function(e, id) {
21389     },
21390
21391     endDrag: function(e) {
21392     }
21393
21394     */
21395
21396 });/*
21397  * Based on:
21398  * Ext JS Library 1.1.1
21399  * Copyright(c) 2006-2007, Ext JS, LLC.
21400  *
21401  * Originally Released Under LGPL - original licence link has changed is not relivant.
21402  *
21403  * Fork - LGPL
21404  * <script type="text/javascript">
21405  */
21406
21407 /**
21408  * @class Roo.dd.DDProxy
21409  * A DragDrop implementation that inserts an empty, bordered div into
21410  * the document that follows the cursor during drag operations.  At the time of
21411  * the click, the frame div is resized to the dimensions of the linked html
21412  * element, and moved to the exact location of the linked element.
21413  *
21414  * References to the "frame" element refer to the single proxy element that
21415  * was created to be dragged in place of all DDProxy elements on the
21416  * page.
21417  *
21418  * @extends Roo.dd.DD
21419  * @constructor
21420  * @param {String} id the id of the linked html element
21421  * @param {String} sGroup the group of related DragDrop objects
21422  * @param {object} config an object containing configurable attributes
21423  *                Valid properties for DDProxy in addition to those in DragDrop:
21424  *                   resizeFrame, centerFrame, dragElId
21425  */
21426 Roo.dd.DDProxy = function(id, sGroup, config) {
21427     if (id) {
21428         this.init(id, sGroup, config);
21429         this.initFrame();
21430     }
21431 };
21432
21433 /**
21434  * The default drag frame div id
21435  * @property Roo.dd.DDProxy.dragElId
21436  * @type String
21437  * @static
21438  */
21439 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21440
21441 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21442
21443     /**
21444      * By default we resize the drag frame to be the same size as the element
21445      * we want to drag (this is to get the frame effect).  We can turn it off
21446      * if we want a different behavior.
21447      * @property resizeFrame
21448      * @type boolean
21449      */
21450     resizeFrame: true,
21451
21452     /**
21453      * By default the frame is positioned exactly where the drag element is, so
21454      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
21455      * you do not have constraints on the obj is to have the drag frame centered
21456      * around the cursor.  Set centerFrame to true for this effect.
21457      * @property centerFrame
21458      * @type boolean
21459      */
21460     centerFrame: false,
21461
21462     /**
21463      * Creates the proxy element if it does not yet exist
21464      * @method createFrame
21465      */
21466     createFrame: function() {
21467         var self = this;
21468         var body = document.body;
21469
21470         if (!body || !body.firstChild) {
21471             setTimeout( function() { self.createFrame(); }, 50 );
21472             return;
21473         }
21474
21475         var div = this.getDragEl();
21476
21477         if (!div) {
21478             div    = document.createElement("div");
21479             div.id = this.dragElId;
21480             var s  = div.style;
21481
21482             s.position   = "absolute";
21483             s.visibility = "hidden";
21484             s.cursor     = "move";
21485             s.border     = "2px solid #aaa";
21486             s.zIndex     = 999;
21487
21488             // appendChild can blow up IE if invoked prior to the window load event
21489             // while rendering a table.  It is possible there are other scenarios
21490             // that would cause this to happen as well.
21491             body.insertBefore(div, body.firstChild);
21492         }
21493     },
21494
21495     /**
21496      * Initialization for the drag frame element.  Must be called in the
21497      * constructor of all subclasses
21498      * @method initFrame
21499      */
21500     initFrame: function() {
21501         this.createFrame();
21502     },
21503
21504     applyConfig: function() {
21505         Roo.dd.DDProxy.superclass.applyConfig.call(this);
21506
21507         this.resizeFrame = (this.config.resizeFrame !== false);
21508         this.centerFrame = (this.config.centerFrame);
21509         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21510     },
21511
21512     /**
21513      * Resizes the drag frame to the dimensions of the clicked object, positions
21514      * it over the object, and finally displays it
21515      * @method showFrame
21516      * @param {int} iPageX X click position
21517      * @param {int} iPageY Y click position
21518      * @private
21519      */
21520     showFrame: function(iPageX, iPageY) {
21521         var el = this.getEl();
21522         var dragEl = this.getDragEl();
21523         var s = dragEl.style;
21524
21525         this._resizeProxy();
21526
21527         if (this.centerFrame) {
21528             this.setDelta( Math.round(parseInt(s.width,  10)/2),
21529                            Math.round(parseInt(s.height, 10)/2) );
21530         }
21531
21532         this.setDragElPos(iPageX, iPageY);
21533
21534         Roo.fly(dragEl).show();
21535     },
21536
21537     /**
21538      * The proxy is automatically resized to the dimensions of the linked
21539      * element when a drag is initiated, unless resizeFrame is set to false
21540      * @method _resizeProxy
21541      * @private
21542      */
21543     _resizeProxy: function() {
21544         if (this.resizeFrame) {
21545             var el = this.getEl();
21546             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21547         }
21548     },
21549
21550     // overrides Roo.dd.DragDrop
21551     b4MouseDown: function(e) {
21552         var x = e.getPageX();
21553         var y = e.getPageY();
21554         this.autoOffset(x, y);
21555         this.setDragElPos(x, y);
21556     },
21557
21558     // overrides Roo.dd.DragDrop
21559     b4StartDrag: function(x, y) {
21560         // show the drag frame
21561         this.showFrame(x, y);
21562     },
21563
21564     // overrides Roo.dd.DragDrop
21565     b4EndDrag: function(e) {
21566         Roo.fly(this.getDragEl()).hide();
21567     },
21568
21569     // overrides Roo.dd.DragDrop
21570     // By default we try to move the element to the last location of the frame.
21571     // This is so that the default behavior mirrors that of Roo.dd.DD.
21572     endDrag: function(e) {
21573
21574         var lel = this.getEl();
21575         var del = this.getDragEl();
21576
21577         // Show the drag frame briefly so we can get its position
21578         del.style.visibility = "";
21579
21580         this.beforeMove();
21581         // Hide the linked element before the move to get around a Safari
21582         // rendering bug.
21583         lel.style.visibility = "hidden";
21584         Roo.dd.DDM.moveToEl(lel, del);
21585         del.style.visibility = "hidden";
21586         lel.style.visibility = "";
21587
21588         this.afterDrag();
21589     },
21590
21591     beforeMove : function(){
21592
21593     },
21594
21595     afterDrag : function(){
21596
21597     },
21598
21599     toString: function() {
21600         return ("DDProxy " + this.id);
21601     }
21602
21603 });
21604 /*
21605  * Based on:
21606  * Ext JS Library 1.1.1
21607  * Copyright(c) 2006-2007, Ext JS, LLC.
21608  *
21609  * Originally Released Under LGPL - original licence link has changed is not relivant.
21610  *
21611  * Fork - LGPL
21612  * <script type="text/javascript">
21613  */
21614
21615  /**
21616  * @class Roo.dd.DDTarget
21617  * A DragDrop implementation that does not move, but can be a drop
21618  * target.  You would get the same result by simply omitting implementation
21619  * for the event callbacks, but this way we reduce the processing cost of the
21620  * event listener and the callbacks.
21621  * @extends Roo.dd.DragDrop
21622  * @constructor
21623  * @param {String} id the id of the element that is a drop target
21624  * @param {String} sGroup the group of related DragDrop objects
21625  * @param {object} config an object containing configurable attributes
21626  *                 Valid properties for DDTarget in addition to those in
21627  *                 DragDrop:
21628  *                    none
21629  */
21630 Roo.dd.DDTarget = function(id, sGroup, config) {
21631     if (id) {
21632         this.initTarget(id, sGroup, config);
21633     }
21634     if (config && (config.listeners || config.events)) { 
21635         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21636             listeners : config.listeners || {}, 
21637             events : config.events || {} 
21638         });    
21639     }
21640 };
21641
21642 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21643 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21644     toString: function() {
21645         return ("DDTarget " + this.id);
21646     }
21647 });
21648 /*
21649  * Based on:
21650  * Ext JS Library 1.1.1
21651  * Copyright(c) 2006-2007, Ext JS, LLC.
21652  *
21653  * Originally Released Under LGPL - original licence link has changed is not relivant.
21654  *
21655  * Fork - LGPL
21656  * <script type="text/javascript">
21657  */
21658  
21659
21660 /**
21661  * @class Roo.dd.ScrollManager
21662  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21663  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21664  * @singleton
21665  */
21666 Roo.dd.ScrollManager = function(){
21667     var ddm = Roo.dd.DragDropMgr;
21668     var els = {};
21669     var dragEl = null;
21670     var proc = {};
21671     
21672     
21673     
21674     var onStop = function(e){
21675         dragEl = null;
21676         clearProc();
21677     };
21678     
21679     var triggerRefresh = function(){
21680         if(ddm.dragCurrent){
21681              ddm.refreshCache(ddm.dragCurrent.groups);
21682         }
21683     };
21684     
21685     var doScroll = function(){
21686         if(ddm.dragCurrent){
21687             var dds = Roo.dd.ScrollManager;
21688             if(!dds.animate){
21689                 if(proc.el.scroll(proc.dir, dds.increment)){
21690                     triggerRefresh();
21691                 }
21692             }else{
21693                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21694             }
21695         }
21696     };
21697     
21698     var clearProc = function(){
21699         if(proc.id){
21700             clearInterval(proc.id);
21701         }
21702         proc.id = 0;
21703         proc.el = null;
21704         proc.dir = "";
21705     };
21706     
21707     var startProc = function(el, dir){
21708          Roo.log('scroll startproc');
21709         clearProc();
21710         proc.el = el;
21711         proc.dir = dir;
21712         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21713     };
21714     
21715     var onFire = function(e, isDrop){
21716        
21717         if(isDrop || !ddm.dragCurrent){ return; }
21718         var dds = Roo.dd.ScrollManager;
21719         if(!dragEl || dragEl != ddm.dragCurrent){
21720             dragEl = ddm.dragCurrent;
21721             // refresh regions on drag start
21722             dds.refreshCache();
21723         }
21724         
21725         var xy = Roo.lib.Event.getXY(e);
21726         var pt = new Roo.lib.Point(xy[0], xy[1]);
21727         for(var id in els){
21728             var el = els[id], r = el._region;
21729             if(r && r.contains(pt) && el.isScrollable()){
21730                 if(r.bottom - pt.y <= dds.thresh){
21731                     if(proc.el != el){
21732                         startProc(el, "down");
21733                     }
21734                     return;
21735                 }else if(r.right - pt.x <= dds.thresh){
21736                     if(proc.el != el){
21737                         startProc(el, "left");
21738                     }
21739                     return;
21740                 }else if(pt.y - r.top <= dds.thresh){
21741                     if(proc.el != el){
21742                         startProc(el, "up");
21743                     }
21744                     return;
21745                 }else if(pt.x - r.left <= dds.thresh){
21746                     if(proc.el != el){
21747                         startProc(el, "right");
21748                     }
21749                     return;
21750                 }
21751             }
21752         }
21753         clearProc();
21754     };
21755     
21756     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21757     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21758     
21759     return {
21760         /**
21761          * Registers new overflow element(s) to auto scroll
21762          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21763          */
21764         register : function(el){
21765             if(el instanceof Array){
21766                 for(var i = 0, len = el.length; i < len; i++) {
21767                         this.register(el[i]);
21768                 }
21769             }else{
21770                 el = Roo.get(el);
21771                 els[el.id] = el;
21772             }
21773             Roo.dd.ScrollManager.els = els;
21774         },
21775         
21776         /**
21777          * Unregisters overflow element(s) so they are no longer scrolled
21778          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21779          */
21780         unregister : function(el){
21781             if(el instanceof Array){
21782                 for(var i = 0, len = el.length; i < len; i++) {
21783                         this.unregister(el[i]);
21784                 }
21785             }else{
21786                 el = Roo.get(el);
21787                 delete els[el.id];
21788             }
21789         },
21790         
21791         /**
21792          * The number of pixels from the edge of a container the pointer needs to be to 
21793          * trigger scrolling (defaults to 25)
21794          * @type Number
21795          */
21796         thresh : 25,
21797         
21798         /**
21799          * The number of pixels to scroll in each scroll increment (defaults to 50)
21800          * @type Number
21801          */
21802         increment : 100,
21803         
21804         /**
21805          * The frequency of scrolls in milliseconds (defaults to 500)
21806          * @type Number
21807          */
21808         frequency : 500,
21809         
21810         /**
21811          * True to animate the scroll (defaults to true)
21812          * @type Boolean
21813          */
21814         animate: true,
21815         
21816         /**
21817          * The animation duration in seconds - 
21818          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21819          * @type Number
21820          */
21821         animDuration: .4,
21822         
21823         /**
21824          * Manually trigger a cache refresh.
21825          */
21826         refreshCache : function(){
21827             for(var id in els){
21828                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21829                     els[id]._region = els[id].getRegion();
21830                 }
21831             }
21832         }
21833     };
21834 }();/*
21835  * Based on:
21836  * Ext JS Library 1.1.1
21837  * Copyright(c) 2006-2007, Ext JS, LLC.
21838  *
21839  * Originally Released Under LGPL - original licence link has changed is not relivant.
21840  *
21841  * Fork - LGPL
21842  * <script type="text/javascript">
21843  */
21844  
21845
21846 /**
21847  * @class Roo.dd.Registry
21848  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21849  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21850  * @singleton
21851  */
21852 Roo.dd.Registry = function(){
21853     var elements = {}; 
21854     var handles = {}; 
21855     var autoIdSeed = 0;
21856
21857     var getId = function(el, autogen){
21858         if(typeof el == "string"){
21859             return el;
21860         }
21861         var id = el.id;
21862         if(!id && autogen !== false){
21863             id = "roodd-" + (++autoIdSeed);
21864             el.id = id;
21865         }
21866         return id;
21867     };
21868     
21869     return {
21870     /**
21871      * Register a drag drop element
21872      * @param {String|HTMLElement} element The id or DOM node to register
21873      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21874      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21875      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21876      * populated in the data object (if applicable):
21877      * <pre>
21878 Value      Description<br />
21879 ---------  ------------------------------------------<br />
21880 handles    Array of DOM nodes that trigger dragging<br />
21881            for the element being registered<br />
21882 isHandle   True if the element passed in triggers<br />
21883            dragging itself, else false
21884 </pre>
21885      */
21886         register : function(el, data){
21887             data = data || {};
21888             if(typeof el == "string"){
21889                 el = document.getElementById(el);
21890             }
21891             data.ddel = el;
21892             elements[getId(el)] = data;
21893             if(data.isHandle !== false){
21894                 handles[data.ddel.id] = data;
21895             }
21896             if(data.handles){
21897                 var hs = data.handles;
21898                 for(var i = 0, len = hs.length; i < len; i++){
21899                         handles[getId(hs[i])] = data;
21900                 }
21901             }
21902         },
21903
21904     /**
21905      * Unregister a drag drop element
21906      * @param {String|HTMLElement}  element The id or DOM node to unregister
21907      */
21908         unregister : function(el){
21909             var id = getId(el, false);
21910             var data = elements[id];
21911             if(data){
21912                 delete elements[id];
21913                 if(data.handles){
21914                     var hs = data.handles;
21915                     for(var i = 0, len = hs.length; i < len; i++){
21916                         delete handles[getId(hs[i], false)];
21917                     }
21918                 }
21919             }
21920         },
21921
21922     /**
21923      * Returns the handle registered for a DOM Node by id
21924      * @param {String|HTMLElement} id The DOM node or id to look up
21925      * @return {Object} handle The custom handle data
21926      */
21927         getHandle : function(id){
21928             if(typeof id != "string"){ // must be element?
21929                 id = id.id;
21930             }
21931             return handles[id];
21932         },
21933
21934     /**
21935      * Returns the handle that is registered for the DOM node that is the target of the event
21936      * @param {Event} e The event
21937      * @return {Object} handle The custom handle data
21938      */
21939         getHandleFromEvent : function(e){
21940             var t = Roo.lib.Event.getTarget(e);
21941             return t ? handles[t.id] : null;
21942         },
21943
21944     /**
21945      * Returns a custom data object that is registered for a DOM node by id
21946      * @param {String|HTMLElement} id The DOM node or id to look up
21947      * @return {Object} data The custom data
21948      */
21949         getTarget : function(id){
21950             if(typeof id != "string"){ // must be element?
21951                 id = id.id;
21952             }
21953             return elements[id];
21954         },
21955
21956     /**
21957      * Returns a custom data object that is registered for the DOM node that is the target of the event
21958      * @param {Event} e The event
21959      * @return {Object} data The custom data
21960      */
21961         getTargetFromEvent : function(e){
21962             var t = Roo.lib.Event.getTarget(e);
21963             return t ? elements[t.id] || handles[t.id] : null;
21964         }
21965     };
21966 }();/*
21967  * Based on:
21968  * Ext JS Library 1.1.1
21969  * Copyright(c) 2006-2007, Ext JS, LLC.
21970  *
21971  * Originally Released Under LGPL - original licence link has changed is not relivant.
21972  *
21973  * Fork - LGPL
21974  * <script type="text/javascript">
21975  */
21976  
21977
21978 /**
21979  * @class Roo.dd.StatusProxy
21980  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21981  * default drag proxy used by all Roo.dd components.
21982  * @constructor
21983  * @param {Object} config
21984  */
21985 Roo.dd.StatusProxy = function(config){
21986     Roo.apply(this, config);
21987     this.id = this.id || Roo.id();
21988     this.el = new Roo.Layer({
21989         dh: {
21990             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21991                 {tag: "div", cls: "x-dd-drop-icon"},
21992                 {tag: "div", cls: "x-dd-drag-ghost"}
21993             ]
21994         }, 
21995         shadow: !config || config.shadow !== false
21996     });
21997     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21998     this.dropStatus = this.dropNotAllowed;
21999 };
22000
22001 Roo.dd.StatusProxy.prototype = {
22002     /**
22003      * @cfg {String} dropAllowed
22004      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22005      */
22006     dropAllowed : "x-dd-drop-ok",
22007     /**
22008      * @cfg {String} dropNotAllowed
22009      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22010      */
22011     dropNotAllowed : "x-dd-drop-nodrop",
22012
22013     /**
22014      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22015      * over the current target element.
22016      * @param {String} cssClass The css class for the new drop status indicator image
22017      */
22018     setStatus : function(cssClass){
22019         cssClass = cssClass || this.dropNotAllowed;
22020         if(this.dropStatus != cssClass){
22021             this.el.replaceClass(this.dropStatus, cssClass);
22022             this.dropStatus = cssClass;
22023         }
22024     },
22025
22026     /**
22027      * Resets the status indicator to the default dropNotAllowed value
22028      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22029      */
22030     reset : function(clearGhost){
22031         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22032         this.dropStatus = this.dropNotAllowed;
22033         if(clearGhost){
22034             this.ghost.update("");
22035         }
22036     },
22037
22038     /**
22039      * Updates the contents of the ghost element
22040      * @param {String} html The html that will replace the current innerHTML of the ghost element
22041      */
22042     update : function(html){
22043         if(typeof html == "string"){
22044             this.ghost.update(html);
22045         }else{
22046             this.ghost.update("");
22047             html.style.margin = "0";
22048             this.ghost.dom.appendChild(html);
22049         }
22050         // ensure float = none set?? cant remember why though.
22051         var el = this.ghost.dom.firstChild;
22052                 if(el){
22053                         Roo.fly(el).setStyle('float', 'none');
22054                 }
22055     },
22056     
22057     /**
22058      * Returns the underlying proxy {@link Roo.Layer}
22059      * @return {Roo.Layer} el
22060     */
22061     getEl : function(){
22062         return this.el;
22063     },
22064
22065     /**
22066      * Returns the ghost element
22067      * @return {Roo.Element} el
22068      */
22069     getGhost : function(){
22070         return this.ghost;
22071     },
22072
22073     /**
22074      * Hides the proxy
22075      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22076      */
22077     hide : function(clear){
22078         this.el.hide();
22079         if(clear){
22080             this.reset(true);
22081         }
22082     },
22083
22084     /**
22085      * Stops the repair animation if it's currently running
22086      */
22087     stop : function(){
22088         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22089             this.anim.stop();
22090         }
22091     },
22092
22093     /**
22094      * Displays this proxy
22095      */
22096     show : function(){
22097         this.el.show();
22098     },
22099
22100     /**
22101      * Force the Layer to sync its shadow and shim positions to the element
22102      */
22103     sync : function(){
22104         this.el.sync();
22105     },
22106
22107     /**
22108      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
22109      * invalid drop operation by the item being dragged.
22110      * @param {Array} xy The XY position of the element ([x, y])
22111      * @param {Function} callback The function to call after the repair is complete
22112      * @param {Object} scope The scope in which to execute the callback
22113      */
22114     repair : function(xy, callback, scope){
22115         this.callback = callback;
22116         this.scope = scope;
22117         if(xy && this.animRepair !== false){
22118             this.el.addClass("x-dd-drag-repair");
22119             this.el.hideUnders(true);
22120             this.anim = this.el.shift({
22121                 duration: this.repairDuration || .5,
22122                 easing: 'easeOut',
22123                 xy: xy,
22124                 stopFx: true,
22125                 callback: this.afterRepair,
22126                 scope: this
22127             });
22128         }else{
22129             this.afterRepair();
22130         }
22131     },
22132
22133     // private
22134     afterRepair : function(){
22135         this.hide(true);
22136         if(typeof this.callback == "function"){
22137             this.callback.call(this.scope || this);
22138         }
22139         this.callback = null;
22140         this.scope = null;
22141     }
22142 };/*
22143  * Based on:
22144  * Ext JS Library 1.1.1
22145  * Copyright(c) 2006-2007, Ext JS, LLC.
22146  *
22147  * Originally Released Under LGPL - original licence link has changed is not relivant.
22148  *
22149  * Fork - LGPL
22150  * <script type="text/javascript">
22151  */
22152
22153 /**
22154  * @class Roo.dd.DragSource
22155  * @extends Roo.dd.DDProxy
22156  * A simple class that provides the basic implementation needed to make any element draggable.
22157  * @constructor
22158  * @param {String/HTMLElement/Element} el The container element
22159  * @param {Object} config
22160  */
22161 Roo.dd.DragSource = function(el, config){
22162     this.el = Roo.get(el);
22163     this.dragData = {};
22164     
22165     Roo.apply(this, config);
22166     
22167     if(!this.proxy){
22168         this.proxy = new Roo.dd.StatusProxy();
22169     }
22170
22171     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22172           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22173     
22174     this.dragging = false;
22175 };
22176
22177 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22178     /**
22179      * @cfg {String} dropAllowed
22180      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22181      */
22182     dropAllowed : "x-dd-drop-ok",
22183     /**
22184      * @cfg {String} dropNotAllowed
22185      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22186      */
22187     dropNotAllowed : "x-dd-drop-nodrop",
22188
22189     /**
22190      * Returns the data object associated with this drag source
22191      * @return {Object} data An object containing arbitrary data
22192      */
22193     getDragData : function(e){
22194         return this.dragData;
22195     },
22196
22197     // private
22198     onDragEnter : function(e, id){
22199         var target = Roo.dd.DragDropMgr.getDDById(id);
22200         this.cachedTarget = target;
22201         if(this.beforeDragEnter(target, e, id) !== false){
22202             if(target.isNotifyTarget){
22203                 var status = target.notifyEnter(this, e, this.dragData);
22204                 this.proxy.setStatus(status);
22205             }else{
22206                 this.proxy.setStatus(this.dropAllowed);
22207             }
22208             
22209             if(this.afterDragEnter){
22210                 /**
22211                  * An empty function by default, but provided so that you can perform a custom action
22212                  * when the dragged item enters the drop target by providing an implementation.
22213                  * @param {Roo.dd.DragDrop} target The drop target
22214                  * @param {Event} e The event object
22215                  * @param {String} id The id of the dragged element
22216                  * @method afterDragEnter
22217                  */
22218                 this.afterDragEnter(target, e, id);
22219             }
22220         }
22221     },
22222
22223     /**
22224      * An empty function by default, but provided so that you can perform a custom action
22225      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22226      * @param {Roo.dd.DragDrop} target The drop target
22227      * @param {Event} e The event object
22228      * @param {String} id The id of the dragged element
22229      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22230      */
22231     beforeDragEnter : function(target, e, id){
22232         return true;
22233     },
22234
22235     // private
22236     alignElWithMouse: function() {
22237         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22238         this.proxy.sync();
22239     },
22240
22241     // private
22242     onDragOver : function(e, id){
22243         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22244         if(this.beforeDragOver(target, e, id) !== false){
22245             if(target.isNotifyTarget){
22246                 var status = target.notifyOver(this, e, this.dragData);
22247                 this.proxy.setStatus(status);
22248             }
22249
22250             if(this.afterDragOver){
22251                 /**
22252                  * An empty function by default, but provided so that you can perform a custom action
22253                  * while the dragged item is over the drop target by providing an implementation.
22254                  * @param {Roo.dd.DragDrop} target The drop target
22255                  * @param {Event} e The event object
22256                  * @param {String} id The id of the dragged element
22257                  * @method afterDragOver
22258                  */
22259                 this.afterDragOver(target, e, id);
22260             }
22261         }
22262     },
22263
22264     /**
22265      * An empty function by default, but provided so that you can perform a custom action
22266      * while the dragged item is over the drop target and optionally cancel the onDragOver.
22267      * @param {Roo.dd.DragDrop} target The drop target
22268      * @param {Event} e The event object
22269      * @param {String} id The id of the dragged element
22270      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22271      */
22272     beforeDragOver : function(target, e, id){
22273         return true;
22274     },
22275
22276     // private
22277     onDragOut : function(e, id){
22278         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22279         if(this.beforeDragOut(target, e, id) !== false){
22280             if(target.isNotifyTarget){
22281                 target.notifyOut(this, e, this.dragData);
22282             }
22283             this.proxy.reset();
22284             if(this.afterDragOut){
22285                 /**
22286                  * An empty function by default, but provided so that you can perform a custom action
22287                  * after the dragged item is dragged out of the target without dropping.
22288                  * @param {Roo.dd.DragDrop} target The drop target
22289                  * @param {Event} e The event object
22290                  * @param {String} id The id of the dragged element
22291                  * @method afterDragOut
22292                  */
22293                 this.afterDragOut(target, e, id);
22294             }
22295         }
22296         this.cachedTarget = null;
22297     },
22298
22299     /**
22300      * An empty function by default, but provided so that you can perform a custom action before the dragged
22301      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22302      * @param {Roo.dd.DragDrop} target The drop target
22303      * @param {Event} e The event object
22304      * @param {String} id The id of the dragged element
22305      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22306      */
22307     beforeDragOut : function(target, e, id){
22308         return true;
22309     },
22310     
22311     // private
22312     onDragDrop : function(e, id){
22313         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22314         if(this.beforeDragDrop(target, e, id) !== false){
22315             if(target.isNotifyTarget){
22316                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22317                     this.onValidDrop(target, e, id);
22318                 }else{
22319                     this.onInvalidDrop(target, e, id);
22320                 }
22321             }else{
22322                 this.onValidDrop(target, e, id);
22323             }
22324             
22325             if(this.afterDragDrop){
22326                 /**
22327                  * An empty function by default, but provided so that you can perform a custom action
22328                  * after a valid drag drop has occurred by providing an implementation.
22329                  * @param {Roo.dd.DragDrop} target The drop target
22330                  * @param {Event} e The event object
22331                  * @param {String} id The id of the dropped element
22332                  * @method afterDragDrop
22333                  */
22334                 this.afterDragDrop(target, e, id);
22335             }
22336         }
22337         delete this.cachedTarget;
22338     },
22339
22340     /**
22341      * An empty function by default, but provided so that you can perform a custom action before the dragged
22342      * item is dropped onto the target and optionally cancel the onDragDrop.
22343      * @param {Roo.dd.DragDrop} target The drop target
22344      * @param {Event} e The event object
22345      * @param {String} id The id of the dragged element
22346      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22347      */
22348     beforeDragDrop : function(target, e, id){
22349         return true;
22350     },
22351
22352     // private
22353     onValidDrop : function(target, e, id){
22354         this.hideProxy();
22355         if(this.afterValidDrop){
22356             /**
22357              * An empty function by default, but provided so that you can perform a custom action
22358              * after a valid drop has occurred by providing an implementation.
22359              * @param {Object} target The target DD 
22360              * @param {Event} e The event object
22361              * @param {String} id The id of the dropped element
22362              * @method afterInvalidDrop
22363              */
22364             this.afterValidDrop(target, e, id);
22365         }
22366     },
22367
22368     // private
22369     getRepairXY : function(e, data){
22370         return this.el.getXY();  
22371     },
22372
22373     // private
22374     onInvalidDrop : function(target, e, id){
22375         this.beforeInvalidDrop(target, e, id);
22376         if(this.cachedTarget){
22377             if(this.cachedTarget.isNotifyTarget){
22378                 this.cachedTarget.notifyOut(this, e, this.dragData);
22379             }
22380             this.cacheTarget = null;
22381         }
22382         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22383
22384         if(this.afterInvalidDrop){
22385             /**
22386              * An empty function by default, but provided so that you can perform a custom action
22387              * after an invalid drop has occurred by providing an implementation.
22388              * @param {Event} e The event object
22389              * @param {String} id The id of the dropped element
22390              * @method afterInvalidDrop
22391              */
22392             this.afterInvalidDrop(e, id);
22393         }
22394     },
22395
22396     // private
22397     afterRepair : function(){
22398         if(Roo.enableFx){
22399             this.el.highlight(this.hlColor || "c3daf9");
22400         }
22401         this.dragging = false;
22402     },
22403
22404     /**
22405      * An empty function by default, but provided so that you can perform a custom action after an invalid
22406      * drop has occurred.
22407      * @param {Roo.dd.DragDrop} target The drop target
22408      * @param {Event} e The event object
22409      * @param {String} id The id of the dragged element
22410      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22411      */
22412     beforeInvalidDrop : function(target, e, id){
22413         return true;
22414     },
22415
22416     // private
22417     handleMouseDown : function(e){
22418         if(this.dragging) {
22419             return;
22420         }
22421         var data = this.getDragData(e);
22422         if(data && this.onBeforeDrag(data, e) !== false){
22423             this.dragData = data;
22424             this.proxy.stop();
22425             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22426         } 
22427     },
22428
22429     /**
22430      * An empty function by default, but provided so that you can perform a custom action before the initial
22431      * drag event begins and optionally cancel it.
22432      * @param {Object} data An object containing arbitrary data to be shared with drop targets
22433      * @param {Event} e The event object
22434      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22435      */
22436     onBeforeDrag : function(data, e){
22437         return true;
22438     },
22439
22440     /**
22441      * An empty function by default, but provided so that you can perform a custom action once the initial
22442      * drag event has begun.  The drag cannot be canceled from this function.
22443      * @param {Number} x The x position of the click on the dragged object
22444      * @param {Number} y The y position of the click on the dragged object
22445      */
22446     onStartDrag : Roo.emptyFn,
22447
22448     // private - YUI override
22449     startDrag : function(x, y){
22450         this.proxy.reset();
22451         this.dragging = true;
22452         this.proxy.update("");
22453         this.onInitDrag(x, y);
22454         this.proxy.show();
22455     },
22456
22457     // private
22458     onInitDrag : function(x, y){
22459         var clone = this.el.dom.cloneNode(true);
22460         clone.id = Roo.id(); // prevent duplicate ids
22461         this.proxy.update(clone);
22462         this.onStartDrag(x, y);
22463         return true;
22464     },
22465
22466     /**
22467      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22468      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22469      */
22470     getProxy : function(){
22471         return this.proxy;  
22472     },
22473
22474     /**
22475      * Hides the drag source's {@link Roo.dd.StatusProxy}
22476      */
22477     hideProxy : function(){
22478         this.proxy.hide();  
22479         this.proxy.reset(true);
22480         this.dragging = false;
22481     },
22482
22483     // private
22484     triggerCacheRefresh : function(){
22485         Roo.dd.DDM.refreshCache(this.groups);
22486     },
22487
22488     // private - override to prevent hiding
22489     b4EndDrag: function(e) {
22490     },
22491
22492     // private - override to prevent moving
22493     endDrag : function(e){
22494         this.onEndDrag(this.dragData, e);
22495     },
22496
22497     // private
22498     onEndDrag : function(data, e){
22499     },
22500     
22501     // private - pin to cursor
22502     autoOffset : function(x, y) {
22503         this.setDelta(-12, -20);
22504     }    
22505 });/*
22506  * Based on:
22507  * Ext JS Library 1.1.1
22508  * Copyright(c) 2006-2007, Ext JS, LLC.
22509  *
22510  * Originally Released Under LGPL - original licence link has changed is not relivant.
22511  *
22512  * Fork - LGPL
22513  * <script type="text/javascript">
22514  */
22515
22516
22517 /**
22518  * @class Roo.dd.DropTarget
22519  * @extends Roo.dd.DDTarget
22520  * A simple class that provides the basic implementation needed to make any element a drop target that can have
22521  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
22522  * @constructor
22523  * @param {String/HTMLElement/Element} el The container element
22524  * @param {Object} config
22525  */
22526 Roo.dd.DropTarget = function(el, config){
22527     this.el = Roo.get(el);
22528     
22529     var listeners = false; ;
22530     if (config && config.listeners) {
22531         listeners= config.listeners;
22532         delete config.listeners;
22533     }
22534     Roo.apply(this, config);
22535     
22536     if(this.containerScroll){
22537         Roo.dd.ScrollManager.register(this.el);
22538     }
22539     this.addEvents( {
22540          /**
22541          * @scope Roo.dd.DropTarget
22542          */
22543          
22544          /**
22545          * @event enter
22546          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22547          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
22548          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
22549          * 
22550          * IMPORTANT : it should set this.overClass and this.dropAllowed
22551          * 
22552          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22553          * @param {Event} e The event
22554          * @param {Object} data An object containing arbitrary data supplied by the drag source
22555          */
22556         "enter" : true,
22557         
22558          /**
22559          * @event over
22560          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22561          * This method will be called on every mouse movement while the drag source is over the drop target.
22562          * This default implementation simply returns the dropAllowed config value.
22563          * 
22564          * IMPORTANT : it should set this.dropAllowed
22565          * 
22566          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22567          * @param {Event} e The event
22568          * @param {Object} data An object containing arbitrary data supplied by the drag source
22569          
22570          */
22571         "over" : true,
22572         /**
22573          * @event out
22574          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22575          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
22576          * overClass (if any) from the drop element.
22577          * 
22578          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22579          * @param {Event} e The event
22580          * @param {Object} data An object containing arbitrary data supplied by the drag source
22581          */
22582          "out" : true,
22583          
22584         /**
22585          * @event drop
22586          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22587          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
22588          * implementation that does something to process the drop event and returns true so that the drag source's
22589          * repair action does not run.
22590          * 
22591          * IMPORTANT : it should set this.success
22592          * 
22593          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22594          * @param {Event} e The event
22595          * @param {Object} data An object containing arbitrary data supplied by the drag source
22596         */
22597          "drop" : true
22598     });
22599             
22600      
22601     Roo.dd.DropTarget.superclass.constructor.call(  this, 
22602         this.el.dom, 
22603         this.ddGroup || this.group,
22604         {
22605             isTarget: true,
22606             listeners : listeners || {} 
22607            
22608         
22609         }
22610     );
22611
22612 };
22613
22614 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22615     /**
22616      * @cfg {String} overClass
22617      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22618      */
22619      /**
22620      * @cfg {String} ddGroup
22621      * The drag drop group to handle drop events for
22622      */
22623      
22624     /**
22625      * @cfg {String} dropAllowed
22626      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22627      */
22628     dropAllowed : "x-dd-drop-ok",
22629     /**
22630      * @cfg {String} dropNotAllowed
22631      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22632      */
22633     dropNotAllowed : "x-dd-drop-nodrop",
22634     /**
22635      * @cfg {boolean} success
22636      * set this after drop listener.. 
22637      */
22638     success : false,
22639     /**
22640      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22641      * if the drop point is valid for over/enter..
22642      */
22643     valid : false,
22644     // private
22645     isTarget : true,
22646
22647     // private
22648     isNotifyTarget : true,
22649     
22650     /**
22651      * @hide
22652      */
22653     notifyEnter : function(dd, e, data)
22654     {
22655         this.valid = true;
22656         this.fireEvent('enter', dd, e, data);
22657         if(this.overClass){
22658             this.el.addClass(this.overClass);
22659         }
22660         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22661             this.valid ? this.dropAllowed : this.dropNotAllowed
22662         );
22663     },
22664
22665     /**
22666      * @hide
22667      */
22668     notifyOver : function(dd, e, data)
22669     {
22670         this.valid = true;
22671         this.fireEvent('over', dd, e, data);
22672         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22673             this.valid ? this.dropAllowed : this.dropNotAllowed
22674         );
22675     },
22676
22677     /**
22678      * @hide
22679      */
22680     notifyOut : function(dd, e, data)
22681     {
22682         this.fireEvent('out', dd, e, data);
22683         if(this.overClass){
22684             this.el.removeClass(this.overClass);
22685         }
22686     },
22687
22688     /**
22689      * @hide
22690      */
22691     notifyDrop : function(dd, e, data)
22692     {
22693         this.success = false;
22694         this.fireEvent('drop', dd, e, data);
22695         return this.success;
22696     }
22697 });/*
22698  * Based on:
22699  * Ext JS Library 1.1.1
22700  * Copyright(c) 2006-2007, Ext JS, LLC.
22701  *
22702  * Originally Released Under LGPL - original licence link has changed is not relivant.
22703  *
22704  * Fork - LGPL
22705  * <script type="text/javascript">
22706  */
22707
22708
22709 /**
22710  * @class Roo.dd.DragZone
22711  * @extends Roo.dd.DragSource
22712  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22713  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22714  * @constructor
22715  * @param {String/HTMLElement/Element} el The container element
22716  * @param {Object} config
22717  */
22718 Roo.dd.DragZone = function(el, config){
22719     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22720     if(this.containerScroll){
22721         Roo.dd.ScrollManager.register(this.el);
22722     }
22723 };
22724
22725 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22726     /**
22727      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22728      * for auto scrolling during drag operations.
22729      */
22730     /**
22731      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22732      * method after a failed drop (defaults to "c3daf9" - light blue)
22733      */
22734
22735     /**
22736      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22737      * for a valid target to drag based on the mouse down. Override this method
22738      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22739      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22740      * @param {EventObject} e The mouse down event
22741      * @return {Object} The dragData
22742      */
22743     getDragData : function(e){
22744         return Roo.dd.Registry.getHandleFromEvent(e);
22745     },
22746     
22747     /**
22748      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22749      * this.dragData.ddel
22750      * @param {Number} x The x position of the click on the dragged object
22751      * @param {Number} y The y position of the click on the dragged object
22752      * @return {Boolean} true to continue the drag, false to cancel
22753      */
22754     onInitDrag : function(x, y){
22755         this.proxy.update(this.dragData.ddel.cloneNode(true));
22756         this.onStartDrag(x, y);
22757         return true;
22758     },
22759     
22760     /**
22761      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22762      */
22763     afterRepair : function(){
22764         if(Roo.enableFx){
22765             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22766         }
22767         this.dragging = false;
22768     },
22769
22770     /**
22771      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22772      * the XY of this.dragData.ddel
22773      * @param {EventObject} e The mouse up event
22774      * @return {Array} The xy location (e.g. [100, 200])
22775      */
22776     getRepairXY : function(e){
22777         return Roo.Element.fly(this.dragData.ddel).getXY();  
22778     }
22779 });/*
22780  * Based on:
22781  * Ext JS Library 1.1.1
22782  * Copyright(c) 2006-2007, Ext JS, LLC.
22783  *
22784  * Originally Released Under LGPL - original licence link has changed is not relivant.
22785  *
22786  * Fork - LGPL
22787  * <script type="text/javascript">
22788  */
22789 /**
22790  * @class Roo.dd.DropZone
22791  * @extends Roo.dd.DropTarget
22792  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22793  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22794  * @constructor
22795  * @param {String/HTMLElement/Element} el The container element
22796  * @param {Object} config
22797  */
22798 Roo.dd.DropZone = function(el, config){
22799     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22800 };
22801
22802 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22803     /**
22804      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22805      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22806      * provide your own custom lookup.
22807      * @param {Event} e The event
22808      * @return {Object} data The custom data
22809      */
22810     getTargetFromEvent : function(e){
22811         return Roo.dd.Registry.getTargetFromEvent(e);
22812     },
22813
22814     /**
22815      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22816      * that it has registered.  This method has no default implementation and should be overridden to provide
22817      * node-specific processing if necessary.
22818      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22819      * {@link #getTargetFromEvent} for this node)
22820      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22821      * @param {Event} e The event
22822      * @param {Object} data An object containing arbitrary data supplied by the drag source
22823      */
22824     onNodeEnter : function(n, dd, e, data){
22825         
22826     },
22827
22828     /**
22829      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22830      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22831      * overridden to provide the proper feedback.
22832      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22833      * {@link #getTargetFromEvent} for this node)
22834      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22835      * @param {Event} e The event
22836      * @param {Object} data An object containing arbitrary data supplied by the drag source
22837      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22838      * underlying {@link Roo.dd.StatusProxy} can be updated
22839      */
22840     onNodeOver : function(n, dd, e, data){
22841         return this.dropAllowed;
22842     },
22843
22844     /**
22845      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22846      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22847      * node-specific processing if necessary.
22848      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22849      * {@link #getTargetFromEvent} for this node)
22850      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22851      * @param {Event} e The event
22852      * @param {Object} data An object containing arbitrary data supplied by the drag source
22853      */
22854     onNodeOut : function(n, dd, e, data){
22855         
22856     },
22857
22858     /**
22859      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22860      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22861      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22862      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22863      * {@link #getTargetFromEvent} for this node)
22864      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22865      * @param {Event} e The event
22866      * @param {Object} data An object containing arbitrary data supplied by the drag source
22867      * @return {Boolean} True if the drop was valid, else false
22868      */
22869     onNodeDrop : function(n, dd, e, data){
22870         return false;
22871     },
22872
22873     /**
22874      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22875      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22876      * it should be overridden to provide the proper feedback if necessary.
22877      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22878      * @param {Event} e The event
22879      * @param {Object} data An object containing arbitrary data supplied by the drag source
22880      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22881      * underlying {@link Roo.dd.StatusProxy} can be updated
22882      */
22883     onContainerOver : function(dd, e, data){
22884         return this.dropNotAllowed;
22885     },
22886
22887     /**
22888      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22889      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22890      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22891      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22892      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22893      * @param {Event} e The event
22894      * @param {Object} data An object containing arbitrary data supplied by the drag source
22895      * @return {Boolean} True if the drop was valid, else false
22896      */
22897     onContainerDrop : function(dd, e, data){
22898         return false;
22899     },
22900
22901     /**
22902      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22903      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22904      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22905      * you should override this method and provide a custom implementation.
22906      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22907      * @param {Event} e The event
22908      * @param {Object} data An object containing arbitrary data supplied by the drag source
22909      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22910      * underlying {@link Roo.dd.StatusProxy} can be updated
22911      */
22912     notifyEnter : function(dd, e, data){
22913         return this.dropNotAllowed;
22914     },
22915
22916     /**
22917      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22918      * This method will be called on every mouse movement while the drag source is over the drop zone.
22919      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22920      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22921      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22922      * registered node, it will call {@link #onContainerOver}.
22923      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22924      * @param {Event} e The event
22925      * @param {Object} data An object containing arbitrary data supplied by the drag source
22926      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22927      * underlying {@link Roo.dd.StatusProxy} can be updated
22928      */
22929     notifyOver : function(dd, e, data){
22930         var n = this.getTargetFromEvent(e);
22931         if(!n){ // not over valid drop target
22932             if(this.lastOverNode){
22933                 this.onNodeOut(this.lastOverNode, dd, e, data);
22934                 this.lastOverNode = null;
22935             }
22936             return this.onContainerOver(dd, e, data);
22937         }
22938         if(this.lastOverNode != n){
22939             if(this.lastOverNode){
22940                 this.onNodeOut(this.lastOverNode, dd, e, data);
22941             }
22942             this.onNodeEnter(n, dd, e, data);
22943             this.lastOverNode = n;
22944         }
22945         return this.onNodeOver(n, dd, e, data);
22946     },
22947
22948     /**
22949      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22950      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22951      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22952      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22953      * @param {Event} e The event
22954      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22955      */
22956     notifyOut : function(dd, e, data){
22957         if(this.lastOverNode){
22958             this.onNodeOut(this.lastOverNode, dd, e, data);
22959             this.lastOverNode = null;
22960         }
22961     },
22962
22963     /**
22964      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22965      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22966      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22967      * otherwise it will call {@link #onContainerDrop}.
22968      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22969      * @param {Event} e The event
22970      * @param {Object} data An object containing arbitrary data supplied by the drag source
22971      * @return {Boolean} True if the drop was valid, else false
22972      */
22973     notifyDrop : function(dd, e, data){
22974         if(this.lastOverNode){
22975             this.onNodeOut(this.lastOverNode, dd, e, data);
22976             this.lastOverNode = null;
22977         }
22978         var n = this.getTargetFromEvent(e);
22979         return n ?
22980             this.onNodeDrop(n, dd, e, data) :
22981             this.onContainerDrop(dd, e, data);
22982     },
22983
22984     // private
22985     triggerCacheRefresh : function(){
22986         Roo.dd.DDM.refreshCache(this.groups);
22987     }  
22988 });