roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             if(window.location.href.indexOf("localhost") !== -1) {
347                 return;
348             }
349             
350             console.log(s);
351         },
352         /**
353          * 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.
354          * @param {Object} o
355          * @return {String}
356          */
357         urlEncode : function(o){
358             if(!o){
359                 return "";
360             }
361             var buf = [];
362             for(var key in o){
363                 var ov = o[key], k = Roo.encodeURIComponent(key);
364                 var type = typeof ov;
365                 if(type == 'undefined'){
366                     buf.push(k, "=&");
367                 }else if(type != "function" && type != "object"){
368                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
369                 }else if(ov instanceof Array){
370                     if (ov.length) {
371                             for(var i = 0, len = ov.length; i < len; i++) {
372                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
373                             }
374                         } else {
375                             buf.push(k, "=&");
376                         }
377                 }
378             }
379             buf.pop();
380             return buf.join("");
381         },
382          /**
383          * Safe version of encodeURIComponent
384          * @param {String} data 
385          * @return {String} 
386          */
387         
388         encodeURIComponent : function (data)
389         {
390             try {
391                 return encodeURIComponent(data);
392             } catch(e) {} // should be an uri encode error.
393             
394             if (data == '' || data == null){
395                return '';
396             }
397             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
398             function nibble_to_hex(nibble){
399                 var chars = '0123456789ABCDEF';
400                 return chars.charAt(nibble);
401             }
402             data = data.toString();
403             var buffer = '';
404             for(var i=0; i<data.length; i++){
405                 var c = data.charCodeAt(i);
406                 var bs = new Array();
407                 if (c > 0x10000){
408                         // 4 bytes
409                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
410                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
411                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
412                     bs[3] = 0x80 | (c & 0x3F);
413                 }else if (c > 0x800){
414                          // 3 bytes
415                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
416                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
417                     bs[2] = 0x80 | (c & 0x3F);
418                 }else if (c > 0x80){
419                        // 2 bytes
420                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
421                     bs[1] = 0x80 | (c & 0x3F);
422                 }else{
423                         // 1 byte
424                     bs[0] = c;
425                 }
426                 for(var j=0; j<bs.length; j++){
427                     var b = bs[j];
428                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
429                             + nibble_to_hex(b &0x0F);
430                     buffer += '%'+hex;
431                }
432             }
433             return buffer;    
434              
435         },
436
437         /**
438          * 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]}.
439          * @param {String} string
440          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
441          * @return {Object} A literal with members
442          */
443         urlDecode : function(string, overwrite){
444             if(!string || !string.length){
445                 return {};
446             }
447             var obj = {};
448             var pairs = string.split('&');
449             var pair, name, value;
450             for(var i = 0, len = pairs.length; i < len; i++){
451                 pair = pairs[i].split('=');
452                 name = decodeURIComponent(pair[0]);
453                 value = decodeURIComponent(pair[1]);
454                 if(overwrite !== true){
455                     if(typeof obj[name] == "undefined"){
456                         obj[name] = value;
457                     }else if(typeof obj[name] == "string"){
458                         obj[name] = [obj[name]];
459                         obj[name].push(value);
460                     }else{
461                         obj[name].push(value);
462                     }
463                 }else{
464                     obj[name] = value;
465                 }
466             }
467             return obj;
468         },
469
470         /**
471          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
472          * passed array is not really an array, your function is called once with it.
473          * The supplied function is called with (Object item, Number index, Array allItems).
474          * @param {Array/NodeList/Mixed} array
475          * @param {Function} fn
476          * @param {Object} scope
477          */
478         each : function(array, fn, scope){
479             if(typeof array.length == "undefined" || typeof array == "string"){
480                 array = [array];
481             }
482             for(var i = 0, len = array.length; i < len; i++){
483                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484             }
485         },
486
487         // deprecated
488         combine : function(){
489             var as = arguments, l = as.length, r = [];
490             for(var i = 0; i < l; i++){
491                 var a = as[i];
492                 if(a instanceof Array){
493                     r = r.concat(a);
494                 }else if(a.length !== undefined && !a.substr){
495                     r = r.concat(Array.prototype.slice.call(a, 0));
496                 }else{
497                     r.push(a);
498                 }
499             }
500             return r;
501         },
502
503         /**
504          * Escapes the passed string for use in a regular expression
505          * @param {String} str
506          * @return {String}
507          */
508         escapeRe : function(s) {
509             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
510         },
511
512         // internal
513         callback : function(cb, scope, args, delay){
514             if(typeof cb == "function"){
515                 if(delay){
516                     cb.defer(delay, scope, args || []);
517                 }else{
518                     cb.apply(scope, args || []);
519                 }
520             }
521         },
522
523         /**
524          * Return the dom node for the passed string (id), dom node, or Roo.Element
525          * @param {String/HTMLElement/Roo.Element} el
526          * @return HTMLElement
527          */
528         getDom : function(el){
529             if(!el){
530                 return null;
531             }
532             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
533         },
534
535         /**
536         * Shorthand for {@link Roo.ComponentMgr#get}
537         * @param {String} id
538         * @return Roo.Component
539         */
540         getCmp : function(id){
541             return Roo.ComponentMgr.get(id);
542         },
543          
544         num : function(v, defaultValue){
545             if(typeof v != 'number'){
546                 return defaultValue;
547             }
548             return v;
549         },
550
551         destroy : function(){
552             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
553                 var as = a[i];
554                 if(as){
555                     if(as.dom){
556                         as.removeAllListeners();
557                         as.remove();
558                         continue;
559                     }
560                     if(typeof as.purgeListeners == 'function'){
561                         as.purgeListeners();
562                     }
563                     if(typeof as.destroy == 'function'){
564                         as.destroy();
565                     }
566                 }
567             }
568         },
569
570         // inpired by a similar function in mootools library
571         /**
572          * Returns the type of object that is passed in. If the object passed in is null or undefined it
573          * return false otherwise it returns one of the following values:<ul>
574          * <li><b>string</b>: If the object passed is a string</li>
575          * <li><b>number</b>: If the object passed is a number</li>
576          * <li><b>boolean</b>: If the object passed is a boolean value</li>
577          * <li><b>function</b>: If the object passed is a function reference</li>
578          * <li><b>object</b>: If the object passed is an object</li>
579          * <li><b>array</b>: If the object passed is an array</li>
580          * <li><b>regexp</b>: If the object passed is a regular expression</li>
581          * <li><b>element</b>: If the object passed is a DOM Element</li>
582          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
583          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
584          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
585          * @param {Mixed} object
586          * @return {String}
587          */
588         type : function(o){
589             if(o === undefined || o === null){
590                 return false;
591             }
592             if(o.htmlElement){
593                 return 'element';
594             }
595             var t = typeof o;
596             if(t == 'object' && o.nodeName) {
597                 switch(o.nodeType) {
598                     case 1: return 'element';
599                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
600                 }
601             }
602             if(t == 'object' || t == 'function') {
603                 switch(o.constructor) {
604                     case Array: return 'array';
605                     case RegExp: return 'regexp';
606                 }
607                 if(typeof o.length == 'number' && typeof o.item == 'function') {
608                     return 'nodelist';
609                 }
610             }
611             return t;
612         },
613
614         /**
615          * Returns true if the passed value is null, undefined or an empty string (optional).
616          * @param {Mixed} value The value to test
617          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
618          * @return {Boolean}
619          */
620         isEmpty : function(v, allowBlank){
621             return v === null || v === undefined || (!allowBlank ? v === '' : false);
622         },
623         
624         /** @type Boolean */
625         isOpera : isOpera,
626         /** @type Boolean */
627         isSafari : isSafari,
628         /** @type Boolean */
629         isFirefox : isFirefox,
630         /** @type Boolean */
631         isIE : isIE,
632         /** @type Boolean */
633         isIE7 : isIE7,
634         /** @type Boolean */
635         isIE11 : isIE11,
636         /** @type Boolean */
637         isEdge : isEdge,
638         /** @type Boolean */
639         isGecko : isGecko,
640         /** @type Boolean */
641         isBorderBox : isBorderBox,
642         /** @type Boolean */
643         isWindows : isWindows,
644         /** @type Boolean */
645         isLinux : isLinux,
646         /** @type Boolean */
647         isMac : isMac,
648         /** @type Boolean */
649         isIOS : isIOS,
650         /** @type Boolean */
651         isAndroid : isAndroid,
652         /** @type Boolean */
653         isTouch : isTouch,
654
655         /**
656          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
657          * you may want to set this to true.
658          * @type Boolean
659          */
660         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661         
662         
663                 
664         /**
665          * Selects a single element as a Roo Element
666          * This is about as close as you can get to jQuery's $('do crazy stuff')
667          * @param {String} selector The selector/xpath query
668          * @param {Node} root (optional) The start of the query (defaults to document).
669          * @return {Roo.Element}
670          */
671         selectNode : function(selector, root) 
672         {
673             var node = Roo.DomQuery.selectNode(selector,root);
674             return node ? Roo.get(node) : new Roo.Element(false);
675         }
676         
677     });
678
679
680 })();
681
682 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
683                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
684                 "Roo.app", "Roo.ux",
685                 "Roo.bootstrap",
686                 "Roo.bootstrap.dash");
687 /*
688  * Based on:
689  * Ext JS Library 1.1.1
690  * Copyright(c) 2006-2007, Ext JS, LLC.
691  *
692  * Originally Released Under LGPL - original licence link has changed is not relivant.
693  *
694  * Fork - LGPL
695  * <script type="text/javascript">
696  */
697
698 (function() {    
699     // wrappedn so fnCleanup is not in global scope...
700     if(Roo.isIE) {
701         function fnCleanUp() {
702             var p = Function.prototype;
703             delete p.createSequence;
704             delete p.defer;
705             delete p.createDelegate;
706             delete p.createCallback;
707             delete p.createInterceptor;
708
709             window.detachEvent("onunload", fnCleanUp);
710         }
711         window.attachEvent("onunload", fnCleanUp);
712     }
713 })();
714
715
716 /**
717  * @class Function
718  * These functions are available on every Function object (any JavaScript function).
719  */
720 Roo.apply(Function.prototype, {
721      /**
722      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
723      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
724      * Will create a function that is bound to those 2 args.
725      * @return {Function} The new function
726     */
727     createCallback : function(/*args...*/){
728         // make args available, in function below
729         var args = arguments;
730         var method = this;
731         return function() {
732             return method.apply(window, args);
733         };
734     },
735
736     /**
737      * Creates a delegate (callback) that sets the scope to obj.
738      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
739      * Will create a function that is automatically scoped to this.
740      * @param {Object} obj (optional) The object for which the scope is set
741      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
742      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
743      *                                             if a number the args are inserted at the specified position
744      * @return {Function} The new function
745      */
746     createDelegate : function(obj, args, appendArgs){
747         var method = this;
748         return function() {
749             var callArgs = args || arguments;
750             if(appendArgs === true){
751                 callArgs = Array.prototype.slice.call(arguments, 0);
752                 callArgs = callArgs.concat(args);
753             }else if(typeof appendArgs == "number"){
754                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
755                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
756                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
757             }
758             return method.apply(obj || window, callArgs);
759         };
760     },
761
762     /**
763      * Calls this function after the number of millseconds specified.
764      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
765      * @param {Object} obj (optional) The object for which the scope is set
766      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
767      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
768      *                                             if a number the args are inserted at the specified position
769      * @return {Number} The timeout id that can be used with clearTimeout
770      */
771     defer : function(millis, obj, args, appendArgs){
772         var fn = this.createDelegate(obj, args, appendArgs);
773         if(millis){
774             return setTimeout(fn, millis);
775         }
776         fn();
777         return 0;
778     },
779     /**
780      * Create a combined function call sequence of the original function + the passed function.
781      * The resulting function returns the results of the original function.
782      * The passed fcn is called with the parameters of the original function
783      * @param {Function} fcn The function to sequence
784      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
785      * @return {Function} The new function
786      */
787     createSequence : function(fcn, scope){
788         if(typeof fcn != "function"){
789             return this;
790         }
791         var method = this;
792         return function() {
793             var retval = method.apply(this || window, arguments);
794             fcn.apply(scope || this || window, arguments);
795             return retval;
796         };
797     },
798
799     /**
800      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
801      * The resulting function returns the results of the original function.
802      * The passed fcn is called with the parameters of the original function.
803      * @addon
804      * @param {Function} fcn The function to call before the original
805      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
806      * @return {Function} The new function
807      */
808     createInterceptor : function(fcn, scope){
809         if(typeof fcn != "function"){
810             return this;
811         }
812         var method = this;
813         return function() {
814             fcn.target = this;
815             fcn.method = method;
816             if(fcn.apply(scope || this || window, arguments) === false){
817                 return;
818             }
819             return method.apply(this || window, arguments);
820         };
821     }
822 });
823 /*
824  * Based on:
825  * Ext JS Library 1.1.1
826  * Copyright(c) 2006-2007, Ext JS, LLC.
827  *
828  * Originally Released Under LGPL - original licence link has changed is not relivant.
829  *
830  * Fork - LGPL
831  * <script type="text/javascript">
832  */
833
834 Roo.applyIf(String, {
835     
836     /** @scope String */
837     
838     /**
839      * Escapes the passed string for ' and \
840      * @param {String} string The string to escape
841      * @return {String} The escaped string
842      * @static
843      */
844     escape : function(string) {
845         return string.replace(/('|\\)/g, "\\$1");
846     },
847
848     /**
849      * Pads the left side of a string with a specified character.  This is especially useful
850      * for normalizing number and date strings.  Example usage:
851      * <pre><code>
852 var s = String.leftPad('123', 5, '0');
853 // s now contains the string: '00123'
854 </code></pre>
855      * @param {String} string The original string
856      * @param {Number} size The total length of the output string
857      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
858      * @return {String} The padded string
859      * @static
860      */
861     leftPad : function (val, size, ch) {
862         var result = new String(val);
863         if(ch === null || ch === undefined || ch === '') {
864             ch = " ";
865         }
866         while (result.length < size) {
867             result = ch + result;
868         }
869         return result;
870     },
871
872     /**
873      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
874      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
875      * <pre><code>
876 var cls = 'my-class', text = 'Some text';
877 var s = String.format('<div class="{0}">{1}</div>', cls, text);
878 // s now contains the string: '<div class="my-class">Some text</div>'
879 </code></pre>
880      * @param {String} string The tokenized string to be formatted
881      * @param {String} value1 The value to replace token {0}
882      * @param {String} value2 Etc...
883      * @return {String} The formatted string
884      * @static
885      */
886     format : function(format){
887         var args = Array.prototype.slice.call(arguments, 1);
888         return format.replace(/\{(\d+)\}/g, function(m, i){
889             return Roo.util.Format.htmlEncode(args[i]);
890         });
891     }
892   
893     
894 });
895
896 /**
897  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
898  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
899  * they are already different, the first value passed in is returned.  Note that this method returns the new value
900  * but does not change the current string.
901  * <pre><code>
902 // alternate sort directions
903 sort = sort.toggle('ASC', 'DESC');
904
905 // instead of conditional logic:
906 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
907 </code></pre>
908  * @param {String} value The value to compare to the current string
909  * @param {String} other The new value to use if the string already equals the first value passed in
910  * @return {String} The new value
911  */
912  
913 String.prototype.toggle = function(value, other){
914     return this == value ? other : value;
915 };
916
917
918 /**
919   * Remove invalid unicode characters from a string 
920   *
921   * @return {String} The clean string
922   */
923 String.prototype.unicodeClean = function () {
924     return this.replace(/[\s\S]/g,
925         function(character) {
926             if (character.charCodeAt()< 256) {
927               return character;
928            }
929            try {
930                 encodeURIComponent(character);
931            } catch(e) { 
932               return '';
933            }
934            return character;
935         }
936     );
937 };
938   
939 /*
940  * Based on:
941  * Ext JS Library 1.1.1
942  * Copyright(c) 2006-2007, Ext JS, LLC.
943  *
944  * Originally Released Under LGPL - original licence link has changed is not relivant.
945  *
946  * Fork - LGPL
947  * <script type="text/javascript">
948  */
949
950  /**
951  * @class Number
952  */
953 Roo.applyIf(Number.prototype, {
954     /**
955      * Checks whether or not the current number is within a desired range.  If the number is already within the
956      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
957      * exceeded.  Note that this method returns the constrained value but does not change the current number.
958      * @param {Number} min The minimum number in the range
959      * @param {Number} max The maximum number in the range
960      * @return {Number} The constrained value if outside the range, otherwise the current value
961      */
962     constrain : function(min, max){
963         return Math.min(Math.max(this, min), max);
964     }
965 });/*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975  /**
976  * @class Array
977  */
978 Roo.applyIf(Array.prototype, {
979     /**
980      * 
981      * Checks whether or not the specified object exists in the array.
982      * @param {Object} o The object to check for
983      * @return {Number} The index of o in the array (or -1 if it is not found)
984      */
985     indexOf : function(o){
986        for (var i = 0, len = this.length; i < len; i++){
987               if(this[i] == o) { return i; }
988        }
989            return -1;
990     },
991
992     /**
993      * Removes the specified object from the array.  If the object is not found nothing happens.
994      * @param {Object} o The object to remove
995      */
996     remove : function(o){
997        var index = this.indexOf(o);
998        if(index != -1){
999            this.splice(index, 1);
1000        }
1001     },
1002     /**
1003      * Map (JS 1.6 compatibility)
1004      * @param {Function} function  to call
1005      */
1006     map : function(fun )
1007     {
1008         var len = this.length >>> 0;
1009         if (typeof fun != "function") {
1010             throw new TypeError();
1011         }
1012         var res = new Array(len);
1013         var thisp = arguments[1];
1014         for (var i = 0; i < len; i++)
1015         {
1016             if (i in this) {
1017                 res[i] = fun.call(thisp, this[i], i, this);
1018             }
1019         }
1020
1021         return res;
1022     }
1023     
1024 });
1025
1026
1027  
1028 /*
1029  * Based on:
1030  * Ext JS Library 1.1.1
1031  * Copyright(c) 2006-2007, Ext JS, LLC.
1032  *
1033  * Originally Released Under LGPL - original licence link has changed is not relivant.
1034  *
1035  * Fork - LGPL
1036  * <script type="text/javascript">
1037  */
1038
1039 /**
1040  * @class Date
1041  *
1042  * The date parsing and format syntax is a subset of
1043  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1044  * supported will provide results equivalent to their PHP versions.
1045  *
1046  * Following is the list of all currently supported formats:
1047  *<pre>
1048 Sample date:
1049 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1050
1051 Format  Output      Description
1052 ------  ----------  --------------------------------------------------------------
1053   d      10         Day of the month, 2 digits with leading zeros
1054   D      Wed        A textual representation of a day, three letters
1055   j      10         Day of the month without leading zeros
1056   l      Wednesday  A full textual representation of the day of the week
1057   S      th         English ordinal day of month suffix, 2 chars (use with j)
1058   w      3          Numeric representation of the day of the week
1059   z      9          The julian date, or day of the year (0-365)
1060   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1061   F      January    A full textual representation of the month
1062   m      01         Numeric representation of a month, with leading zeros
1063   M      Jan        Month name abbreviation, three letters
1064   n      1          Numeric representation of a month, without leading zeros
1065   t      31         Number of days in the given month
1066   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1067   Y      2007       A full numeric representation of a year, 4 digits
1068   y      07         A two digit representation of a year
1069   a      pm         Lowercase Ante meridiem and Post meridiem
1070   A      PM         Uppercase Ante meridiem and Post meridiem
1071   g      3          12-hour format of an hour without leading zeros
1072   G      15         24-hour format of an hour without leading zeros
1073   h      03         12-hour format of an hour with leading zeros
1074   H      15         24-hour format of an hour with leading zeros
1075   i      05         Minutes with leading zeros
1076   s      01         Seconds, with leading zeros
1077   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1078   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1079   T      CST        Timezone setting of the machine running the code
1080   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1081 </pre>
1082  *
1083  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1084  * <pre><code>
1085 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1086 document.write(dt.format('Y-m-d'));                         //2007-01-10
1087 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1088 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
1089  </code></pre>
1090  *
1091  * Here are some standard date/time patterns that you might find helpful.  They
1092  * are not part of the source of Date.js, but to use them you can simply copy this
1093  * block of code into any script that is included after Date.js and they will also become
1094  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1095  * <pre><code>
1096 Date.patterns = {
1097     ISO8601Long:"Y-m-d H:i:s",
1098     ISO8601Short:"Y-m-d",
1099     ShortDate: "n/j/Y",
1100     LongDate: "l, F d, Y",
1101     FullDateTime: "l, F d, Y g:i:s A",
1102     MonthDay: "F d",
1103     ShortTime: "g:i A",
1104     LongTime: "g:i:s A",
1105     SortableDateTime: "Y-m-d\\TH:i:s",
1106     UniversalSortableDateTime: "Y-m-d H:i:sO",
1107     YearMonth: "F, Y"
1108 };
1109 </code></pre>
1110  *
1111  * Example usage:
1112  * <pre><code>
1113 var dt = new Date();
1114 document.write(dt.format(Date.patterns.ShortDate));
1115  </code></pre>
1116  */
1117
1118 /*
1119  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1120  * They generate precompiled functions from date formats instead of parsing and
1121  * processing the pattern every time you format a date.  These functions are available
1122  * on every Date object (any javascript function).
1123  *
1124  * The original article and download are here:
1125  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1126  *
1127  */
1128  
1129  
1130  // was in core
1131 /**
1132  Returns the number of milliseconds between this date and date
1133  @param {Date} date (optional) Defaults to now
1134  @return {Number} The diff in milliseconds
1135  @member Date getElapsed
1136  */
1137 Date.prototype.getElapsed = function(date) {
1138         return Math.abs((date || new Date()).getTime()-this.getTime());
1139 };
1140 // was in date file..
1141
1142
1143 // private
1144 Date.parseFunctions = {count:0};
1145 // private
1146 Date.parseRegexes = [];
1147 // private
1148 Date.formatFunctions = {count:0};
1149
1150 // private
1151 Date.prototype.dateFormat = function(format) {
1152     if (Date.formatFunctions[format] == null) {
1153         Date.createNewFormat(format);
1154     }
1155     var func = Date.formatFunctions[format];
1156     return this[func]();
1157 };
1158
1159
1160 /**
1161  * Formats a date given the supplied format string
1162  * @param {String} format The format string
1163  * @return {String} The formatted date
1164  * @method
1165  */
1166 Date.prototype.format = Date.prototype.dateFormat;
1167
1168 // private
1169 Date.createNewFormat = function(format) {
1170     var funcName = "format" + Date.formatFunctions.count++;
1171     Date.formatFunctions[format] = funcName;
1172     var code = "Date.prototype." + funcName + " = function(){return ";
1173     var special = false;
1174     var ch = '';
1175     for (var i = 0; i < format.length; ++i) {
1176         ch = format.charAt(i);
1177         if (!special && ch == "\\") {
1178             special = true;
1179         }
1180         else if (special) {
1181             special = false;
1182             code += "'" + String.escape(ch) + "' + ";
1183         }
1184         else {
1185             code += Date.getFormatCode(ch);
1186         }
1187     }
1188     /** eval:var:zzzzzzzzzzzzz */
1189     eval(code.substring(0, code.length - 3) + ";}");
1190 };
1191
1192 // private
1193 Date.getFormatCode = function(character) {
1194     switch (character) {
1195     case "d":
1196         return "String.leftPad(this.getDate(), 2, '0') + ";
1197     case "D":
1198         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1199     case "j":
1200         return "this.getDate() + ";
1201     case "l":
1202         return "Date.dayNames[this.getDay()] + ";
1203     case "S":
1204         return "this.getSuffix() + ";
1205     case "w":
1206         return "this.getDay() + ";
1207     case "z":
1208         return "this.getDayOfYear() + ";
1209     case "W":
1210         return "this.getWeekOfYear() + ";
1211     case "F":
1212         return "Date.monthNames[this.getMonth()] + ";
1213     case "m":
1214         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1215     case "M":
1216         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1217     case "n":
1218         return "(this.getMonth() + 1) + ";
1219     case "t":
1220         return "this.getDaysInMonth() + ";
1221     case "L":
1222         return "(this.isLeapYear() ? 1 : 0) + ";
1223     case "Y":
1224         return "this.getFullYear() + ";
1225     case "y":
1226         return "('' + this.getFullYear()).substring(2, 4) + ";
1227     case "a":
1228         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1229     case "A":
1230         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1231     case "g":
1232         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1233     case "G":
1234         return "this.getHours() + ";
1235     case "h":
1236         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1237     case "H":
1238         return "String.leftPad(this.getHours(), 2, '0') + ";
1239     case "i":
1240         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1241     case "s":
1242         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1243     case "O":
1244         return "this.getGMTOffset() + ";
1245     case "P":
1246         return "this.getGMTColonOffset() + ";
1247     case "T":
1248         return "this.getTimezone() + ";
1249     case "Z":
1250         return "(this.getTimezoneOffset() * -60) + ";
1251     default:
1252         return "'" + String.escape(character) + "' + ";
1253     }
1254 };
1255
1256 /**
1257  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1258  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1259  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1260  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1261  * string or the parse operation will fail.
1262  * Example Usage:
1263 <pre><code>
1264 //dt = Fri May 25 2007 (current date)
1265 var dt = new Date();
1266
1267 //dt = Thu May 25 2006 (today's month/day in 2006)
1268 dt = Date.parseDate("2006", "Y");
1269
1270 //dt = Sun Jan 15 2006 (all date parts specified)
1271 dt = Date.parseDate("2006-1-15", "Y-m-d");
1272
1273 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1274 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1275 </code></pre>
1276  * @param {String} input The unparsed date as a string
1277  * @param {String} format The format the date is in
1278  * @return {Date} The parsed date
1279  * @static
1280  */
1281 Date.parseDate = function(input, format) {
1282     if (Date.parseFunctions[format] == null) {
1283         Date.createParser(format);
1284     }
1285     var func = Date.parseFunctions[format];
1286     return Date[func](input);
1287 };
1288 /**
1289  * @private
1290  */
1291
1292 Date.createParser = function(format) {
1293     var funcName = "parse" + Date.parseFunctions.count++;
1294     var regexNum = Date.parseRegexes.length;
1295     var currentGroup = 1;
1296     Date.parseFunctions[format] = funcName;
1297
1298     var code = "Date." + funcName + " = function(input){\n"
1299         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1300         + "var d = new Date();\n"
1301         + "y = d.getFullYear();\n"
1302         + "m = d.getMonth();\n"
1303         + "d = d.getDate();\n"
1304         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1305         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1306         + "if (results && results.length > 0) {";
1307     var regex = "";
1308
1309     var special = false;
1310     var ch = '';
1311     for (var i = 0; i < format.length; ++i) {
1312         ch = format.charAt(i);
1313         if (!special && ch == "\\") {
1314             special = true;
1315         }
1316         else if (special) {
1317             special = false;
1318             regex += String.escape(ch);
1319         }
1320         else {
1321             var obj = Date.formatCodeToRegex(ch, currentGroup);
1322             currentGroup += obj.g;
1323             regex += obj.s;
1324             if (obj.g && obj.c) {
1325                 code += obj.c;
1326             }
1327         }
1328     }
1329
1330     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1331         + "{v = new Date(y, m, d, h, i, s);}\n"
1332         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1333         + "{v = new Date(y, m, d, h, i);}\n"
1334         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1335         + "{v = new Date(y, m, d, h);}\n"
1336         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1337         + "{v = new Date(y, m, d);}\n"
1338         + "else if (y >= 0 && m >= 0)\n"
1339         + "{v = new Date(y, m);}\n"
1340         + "else if (y >= 0)\n"
1341         + "{v = new Date(y);}\n"
1342         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1343         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1344         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1345         + ";}";
1346
1347     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1348     /** eval:var:zzzzzzzzzzzzz */
1349     eval(code);
1350 };
1351
1352 // private
1353 Date.formatCodeToRegex = function(character, currentGroup) {
1354     switch (character) {
1355     case "D":
1356         return {g:0,
1357         c:null,
1358         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1359     case "j":
1360         return {g:1,
1361             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1362             s:"(\\d{1,2})"}; // day of month without leading zeroes
1363     case "d":
1364         return {g:1,
1365             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{2})"}; // day of month with leading zeroes
1367     case "l":
1368         return {g:0,
1369             c:null,
1370             s:"(?:" + Date.dayNames.join("|") + ")"};
1371     case "S":
1372         return {g:0,
1373             c:null,
1374             s:"(?:st|nd|rd|th)"};
1375     case "w":
1376         return {g:0,
1377             c:null,
1378             s:"\\d"};
1379     case "z":
1380         return {g:0,
1381             c:null,
1382             s:"(?:\\d{1,3})"};
1383     case "W":
1384         return {g:0,
1385             c:null,
1386             s:"(?:\\d{2})"};
1387     case "F":
1388         return {g:1,
1389             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1390             s:"(" + Date.monthNames.join("|") + ")"};
1391     case "M":
1392         return {g:1,
1393             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1394             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1395     case "n":
1396         return {g:1,
1397             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1398             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1399     case "m":
1400         return {g:1,
1401             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1402             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1403     case "t":
1404         return {g:0,
1405             c:null,
1406             s:"\\d{1,2}"};
1407     case "L":
1408         return {g:0,
1409             c:null,
1410             s:"(?:1|0)"};
1411     case "Y":
1412         return {g:1,
1413             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1414             s:"(\\d{4})"};
1415     case "y":
1416         return {g:1,
1417             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1418                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1419             s:"(\\d{1,2})"};
1420     case "a":
1421         return {g:1,
1422             c:"if (results[" + currentGroup + "] == 'am') {\n"
1423                 + "if (h == 12) { h = 0; }\n"
1424                 + "} else { if (h < 12) { h += 12; }}",
1425             s:"(am|pm)"};
1426     case "A":
1427         return {g:1,
1428             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1429                 + "if (h == 12) { h = 0; }\n"
1430                 + "} else { if (h < 12) { h += 12; }}",
1431             s:"(AM|PM)"};
1432     case "g":
1433     case "G":
1434         return {g:1,
1435             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1437     case "h":
1438     case "H":
1439         return {g:1,
1440             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1441             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1442     case "i":
1443         return {g:1,
1444             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1445             s:"(\\d{2})"};
1446     case "s":
1447         return {g:1,
1448             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1449             s:"(\\d{2})"};
1450     case "O":
1451         return {g:1,
1452             c:[
1453                 "o = results[", currentGroup, "];\n",
1454                 "var sn = o.substring(0,1);\n", // get + / - sign
1455                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1456                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1457                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1458                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1459             ].join(""),
1460             s:"([+\-]\\d{2,4})"};
1461     
1462     
1463     case "P":
1464         return {g:1,
1465                 c:[
1466                    "o = results[", currentGroup, "];\n",
1467                    "var sn = o.substring(0,1);\n",
1468                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1469                    "var mn = o.substring(4,6) % 60;\n",
1470                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1471                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1472             ].join(""),
1473             s:"([+\-]\\d{4})"};
1474     case "T":
1475         return {g:0,
1476             c:null,
1477             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1478     case "Z":
1479         return {g:1,
1480             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1481                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1482             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1483     default:
1484         return {g:0,
1485             c:null,
1486             s:String.escape(character)};
1487     }
1488 };
1489
1490 /**
1491  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1492  * @return {String} The abbreviated timezone name (e.g. 'CST')
1493  */
1494 Date.prototype.getTimezone = function() {
1495     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1496 };
1497
1498 /**
1499  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1500  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1501  */
1502 Date.prototype.getGMTOffset = function() {
1503     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1504         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1505         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1506 };
1507
1508 /**
1509  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1510  * @return {String} 2-characters representing hours and 2-characters representing minutes
1511  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1512  */
1513 Date.prototype.getGMTColonOffset = function() {
1514         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1515                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1516                 + ":"
1517                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1518 }
1519
1520 /**
1521  * Get the numeric day number of the year, adjusted for leap year.
1522  * @return {Number} 0 through 364 (365 in leap years)
1523  */
1524 Date.prototype.getDayOfYear = function() {
1525     var num = 0;
1526     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1527     for (var i = 0; i < this.getMonth(); ++i) {
1528         num += Date.daysInMonth[i];
1529     }
1530     return num + this.getDate() - 1;
1531 };
1532
1533 /**
1534  * Get the string representation of the numeric week number of the year
1535  * (equivalent to the format specifier 'W').
1536  * @return {String} '00' through '52'
1537  */
1538 Date.prototype.getWeekOfYear = function() {
1539     // Skip to Thursday of this week
1540     var now = this.getDayOfYear() + (4 - this.getDay());
1541     // Find the first Thursday of the year
1542     var jan1 = new Date(this.getFullYear(), 0, 1);
1543     var then = (7 - jan1.getDay() + 4);
1544     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1545 };
1546
1547 /**
1548  * Whether or not the current date is in a leap year.
1549  * @return {Boolean} True if the current date is in a leap year, else false
1550  */
1551 Date.prototype.isLeapYear = function() {
1552     var year = this.getFullYear();
1553     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1554 };
1555
1556 /**
1557  * Get the first day of the current month, adjusted for leap year.  The returned value
1558  * is the numeric day index within the week (0-6) which can be used in conjunction with
1559  * the {@link #monthNames} array to retrieve the textual day name.
1560  * Example:
1561  *<pre><code>
1562 var dt = new Date('1/10/2007');
1563 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1564 </code></pre>
1565  * @return {Number} The day number (0-6)
1566  */
1567 Date.prototype.getFirstDayOfMonth = function() {
1568     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1569     return (day < 0) ? (day + 7) : day;
1570 };
1571
1572 /**
1573  * Get the last day of the current month, adjusted for leap year.  The returned value
1574  * is the numeric day index within the week (0-6) which can be used in conjunction with
1575  * the {@link #monthNames} array to retrieve the textual day name.
1576  * Example:
1577  *<pre><code>
1578 var dt = new Date('1/10/2007');
1579 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1580 </code></pre>
1581  * @return {Number} The day number (0-6)
1582  */
1583 Date.prototype.getLastDayOfMonth = function() {
1584     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1585     return (day < 0) ? (day + 7) : day;
1586 };
1587
1588
1589 /**
1590  * Get the first date of this date's month
1591  * @return {Date}
1592  */
1593 Date.prototype.getFirstDateOfMonth = function() {
1594     return new Date(this.getFullYear(), this.getMonth(), 1);
1595 };
1596
1597 /**
1598  * Get the last date of this date's month
1599  * @return {Date}
1600  */
1601 Date.prototype.getLastDateOfMonth = function() {
1602     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1603 };
1604 /**
1605  * Get the number of days in the current month, adjusted for leap year.
1606  * @return {Number} The number of days in the month
1607  */
1608 Date.prototype.getDaysInMonth = function() {
1609     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1610     return Date.daysInMonth[this.getMonth()];
1611 };
1612
1613 /**
1614  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1615  * @return {String} 'st, 'nd', 'rd' or 'th'
1616  */
1617 Date.prototype.getSuffix = function() {
1618     switch (this.getDate()) {
1619         case 1:
1620         case 21:
1621         case 31:
1622             return "st";
1623         case 2:
1624         case 22:
1625             return "nd";
1626         case 3:
1627         case 23:
1628             return "rd";
1629         default:
1630             return "th";
1631     }
1632 };
1633
1634 // private
1635 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1636
1637 /**
1638  * An array of textual month names.
1639  * Override these values for international dates, for example...
1640  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1641  * @type Array
1642  * @static
1643  */
1644 Date.monthNames =
1645    ["January",
1646     "February",
1647     "March",
1648     "April",
1649     "May",
1650     "June",
1651     "July",
1652     "August",
1653     "September",
1654     "October",
1655     "November",
1656     "December"];
1657
1658 /**
1659  * An array of textual day names.
1660  * Override these values for international dates, for example...
1661  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1662  * @type Array
1663  * @static
1664  */
1665 Date.dayNames =
1666    ["Sunday",
1667     "Monday",
1668     "Tuesday",
1669     "Wednesday",
1670     "Thursday",
1671     "Friday",
1672     "Saturday"];
1673
1674 // private
1675 Date.y2kYear = 50;
1676 // private
1677 Date.monthNumbers = {
1678     Jan:0,
1679     Feb:1,
1680     Mar:2,
1681     Apr:3,
1682     May:4,
1683     Jun:5,
1684     Jul:6,
1685     Aug:7,
1686     Sep:8,
1687     Oct:9,
1688     Nov:10,
1689     Dec:11};
1690
1691 /**
1692  * Creates and returns a new Date instance with the exact same date value as the called instance.
1693  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1694  * variable will also be changed.  When the intention is to create a new variable that will not
1695  * modify the original instance, you should create a clone.
1696  *
1697  * Example of correctly cloning a date:
1698  * <pre><code>
1699 //wrong way:
1700 var orig = new Date('10/1/2006');
1701 var copy = orig;
1702 copy.setDate(5);
1703 document.write(orig);  //returns 'Thu Oct 05 2006'!
1704
1705 //correct way:
1706 var orig = new Date('10/1/2006');
1707 var copy = orig.clone();
1708 copy.setDate(5);
1709 document.write(orig);  //returns 'Thu Oct 01 2006'
1710 </code></pre>
1711  * @return {Date} The new Date instance
1712  */
1713 Date.prototype.clone = function() {
1714         return new Date(this.getTime());
1715 };
1716
1717 /**
1718  * Clears any time information from this date
1719  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1720  @return {Date} this or the clone
1721  */
1722 Date.prototype.clearTime = function(clone){
1723     if(clone){
1724         return this.clone().clearTime();
1725     }
1726     this.setHours(0);
1727     this.setMinutes(0);
1728     this.setSeconds(0);
1729     this.setMilliseconds(0);
1730     return this;
1731 };
1732
1733 // private
1734 // safari setMonth is broken -- check that this is only donw once...
1735 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1736     Date.brokenSetMonth = Date.prototype.setMonth;
1737         Date.prototype.setMonth = function(num){
1738                 if(num <= -1){
1739                         var n = Math.ceil(-num);
1740                         var back_year = Math.ceil(n/12);
1741                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1742                         this.setFullYear(this.getFullYear() - back_year);
1743                         return Date.brokenSetMonth.call(this, month);
1744                 } else {
1745                         return Date.brokenSetMonth.apply(this, arguments);
1746                 }
1747         };
1748 }
1749
1750 /** Date interval constant 
1751 * @static 
1752 * @type String */
1753 Date.MILLI = "ms";
1754 /** Date interval constant 
1755 * @static 
1756 * @type String */
1757 Date.SECOND = "s";
1758 /** Date interval constant 
1759 * @static 
1760 * @type String */
1761 Date.MINUTE = "mi";
1762 /** Date interval constant 
1763 * @static 
1764 * @type String */
1765 Date.HOUR = "h";
1766 /** Date interval constant 
1767 * @static 
1768 * @type String */
1769 Date.DAY = "d";
1770 /** Date interval constant 
1771 * @static 
1772 * @type String */
1773 Date.MONTH = "mo";
1774 /** Date interval constant 
1775 * @static 
1776 * @type String */
1777 Date.YEAR = "y";
1778
1779 /**
1780  * Provides a convenient method of performing basic date arithmetic.  This method
1781  * does not modify the Date instance being called - it creates and returns
1782  * a new Date instance containing the resulting date value.
1783  *
1784  * Examples:
1785  * <pre><code>
1786 //Basic usage:
1787 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1788 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1789
1790 //Negative values will subtract correctly:
1791 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1792 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1793
1794 //You can even chain several calls together in one line!
1795 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1796 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1797  </code></pre>
1798  *
1799  * @param {String} interval   A valid date interval enum value
1800  * @param {Number} value      The amount to add to the current date
1801  * @return {Date} The new Date instance
1802  */
1803 Date.prototype.add = function(interval, value){
1804   var d = this.clone();
1805   if (!interval || value === 0) { return d; }
1806   switch(interval.toLowerCase()){
1807     case Date.MILLI:
1808       d.setMilliseconds(this.getMilliseconds() + value);
1809       break;
1810     case Date.SECOND:
1811       d.setSeconds(this.getSeconds() + value);
1812       break;
1813     case Date.MINUTE:
1814       d.setMinutes(this.getMinutes() + value);
1815       break;
1816     case Date.HOUR:
1817       d.setHours(this.getHours() + value);
1818       break;
1819     case Date.DAY:
1820       d.setDate(this.getDate() + value);
1821       break;
1822     case Date.MONTH:
1823       var day = this.getDate();
1824       if(day > 28){
1825           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1826       }
1827       d.setDate(day);
1828       d.setMonth(this.getMonth() + value);
1829       break;
1830     case Date.YEAR:
1831       d.setFullYear(this.getFullYear() + value);
1832       break;
1833   }
1834   return d;
1835 };
1836 /*
1837  * Based on:
1838  * Ext JS Library 1.1.1
1839  * Copyright(c) 2006-2007, Ext JS, LLC.
1840  *
1841  * Originally Released Under LGPL - original licence link has changed is not relivant.
1842  *
1843  * Fork - LGPL
1844  * <script type="text/javascript">
1845  */
1846
1847 /**
1848  * @class Roo.lib.Dom
1849  * @static
1850  * 
1851  * Dom utils (from YIU afaik)
1852  * 
1853  **/
1854 Roo.lib.Dom = {
1855     /**
1856      * Get the view width
1857      * @param {Boolean} full True will get the full document, otherwise it's the view width
1858      * @return {Number} The width
1859      */
1860      
1861     getViewWidth : function(full) {
1862         return full ? this.getDocumentWidth() : this.getViewportWidth();
1863     },
1864     /**
1865      * Get the view height
1866      * @param {Boolean} full True will get the full document, otherwise it's the view height
1867      * @return {Number} The height
1868      */
1869     getViewHeight : function(full) {
1870         return full ? this.getDocumentHeight() : this.getViewportHeight();
1871     },
1872
1873     getDocumentHeight: function() {
1874         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1875         return Math.max(scrollHeight, this.getViewportHeight());
1876     },
1877
1878     getDocumentWidth: function() {
1879         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1880         return Math.max(scrollWidth, this.getViewportWidth());
1881     },
1882
1883     getViewportHeight: function() {
1884         var height = self.innerHeight;
1885         var mode = document.compatMode;
1886
1887         if ((mode || Roo.isIE) && !Roo.isOpera) {
1888             height = (mode == "CSS1Compat") ?
1889                      document.documentElement.clientHeight :
1890                      document.body.clientHeight;
1891         }
1892
1893         return height;
1894     },
1895
1896     getViewportWidth: function() {
1897         var width = self.innerWidth;
1898         var mode = document.compatMode;
1899
1900         if (mode || Roo.isIE) {
1901             width = (mode == "CSS1Compat") ?
1902                     document.documentElement.clientWidth :
1903                     document.body.clientWidth;
1904         }
1905         return width;
1906     },
1907
1908     isAncestor : function(p, c) {
1909         p = Roo.getDom(p);
1910         c = Roo.getDom(c);
1911         if (!p || !c) {
1912             return false;
1913         }
1914
1915         if (p.contains && !Roo.isSafari) {
1916             return p.contains(c);
1917         } else if (p.compareDocumentPosition) {
1918             return !!(p.compareDocumentPosition(c) & 16);
1919         } else {
1920             var parent = c.parentNode;
1921             while (parent) {
1922                 if (parent == p) {
1923                     return true;
1924                 }
1925                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1926                     return false;
1927                 }
1928                 parent = parent.parentNode;
1929             }
1930             return false;
1931         }
1932     },
1933
1934     getRegion : function(el) {
1935         return Roo.lib.Region.getRegion(el);
1936     },
1937
1938     getY : function(el) {
1939         return this.getXY(el)[1];
1940     },
1941
1942     getX : function(el) {
1943         return this.getXY(el)[0];
1944     },
1945
1946     getXY : function(el) {
1947         var p, pe, b, scroll, bd = document.body;
1948         el = Roo.getDom(el);
1949         var fly = Roo.lib.AnimBase.fly;
1950         if (el.getBoundingClientRect) {
1951             b = el.getBoundingClientRect();
1952             scroll = fly(document).getScroll();
1953             return [b.left + scroll.left, b.top + scroll.top];
1954         }
1955         var x = 0, y = 0;
1956
1957         p = el;
1958
1959         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1960
1961         while (p) {
1962
1963             x += p.offsetLeft;
1964             y += p.offsetTop;
1965
1966             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1967                 hasAbsolute = true;
1968             }
1969
1970             if (Roo.isGecko) {
1971                 pe = fly(p);
1972
1973                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1974                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1975
1976
1977                 x += bl;
1978                 y += bt;
1979
1980
1981                 if (p != el && pe.getStyle('overflow') != 'visible') {
1982                     x += bl;
1983                     y += bt;
1984                 }
1985             }
1986             p = p.offsetParent;
1987         }
1988
1989         if (Roo.isSafari && hasAbsolute) {
1990             x -= bd.offsetLeft;
1991             y -= bd.offsetTop;
1992         }
1993
1994         if (Roo.isGecko && !hasAbsolute) {
1995             var dbd = fly(bd);
1996             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1997             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1998         }
1999
2000         p = el.parentNode;
2001         while (p && p != bd) {
2002             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2003                 x -= p.scrollLeft;
2004                 y -= p.scrollTop;
2005             }
2006             p = p.parentNode;
2007         }
2008         return [x, y];
2009     },
2010  
2011   
2012
2013
2014     setXY : function(el, xy) {
2015         el = Roo.fly(el, '_setXY');
2016         el.position();
2017         var pts = el.translatePoints(xy);
2018         if (xy[0] !== false) {
2019             el.dom.style.left = pts.left + "px";
2020         }
2021         if (xy[1] !== false) {
2022             el.dom.style.top = pts.top + "px";
2023         }
2024     },
2025
2026     setX : function(el, x) {
2027         this.setXY(el, [x, false]);
2028     },
2029
2030     setY : function(el, y) {
2031         this.setXY(el, [false, y]);
2032     }
2033 };
2034 /*
2035  * Portions of this file are based on pieces of Yahoo User Interface Library
2036  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2037  * YUI licensed under the BSD License:
2038  * http://developer.yahoo.net/yui/license.txt
2039  * <script type="text/javascript">
2040  *
2041  */
2042
2043 Roo.lib.Event = function() {
2044     var loadComplete = false;
2045     var listeners = [];
2046     var unloadListeners = [];
2047     var retryCount = 0;
2048     var onAvailStack = [];
2049     var counter = 0;
2050     var lastError = null;
2051
2052     return {
2053         POLL_RETRYS: 200,
2054         POLL_INTERVAL: 20,
2055         EL: 0,
2056         TYPE: 1,
2057         FN: 2,
2058         WFN: 3,
2059         OBJ: 3,
2060         ADJ_SCOPE: 4,
2061         _interval: null,
2062
2063         startInterval: function() {
2064             if (!this._interval) {
2065                 var self = this;
2066                 var callback = function() {
2067                     self._tryPreloadAttach();
2068                 };
2069                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2070
2071             }
2072         },
2073
2074         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2075             onAvailStack.push({ id:         p_id,
2076                 fn:         p_fn,
2077                 obj:        p_obj,
2078                 override:   p_override,
2079                 checkReady: false    });
2080
2081             retryCount = this.POLL_RETRYS;
2082             this.startInterval();
2083         },
2084
2085
2086         addListener: function(el, eventName, fn) {
2087             el = Roo.getDom(el);
2088             if (!el || !fn) {
2089                 return false;
2090             }
2091
2092             if ("unload" == eventName) {
2093                 unloadListeners[unloadListeners.length] =
2094                 [el, eventName, fn];
2095                 return true;
2096             }
2097
2098             var wrappedFn = function(e) {
2099                 return fn(Roo.lib.Event.getEvent(e));
2100             };
2101
2102             var li = [el, eventName, fn, wrappedFn];
2103
2104             var index = listeners.length;
2105             listeners[index] = li;
2106
2107             this.doAdd(el, eventName, wrappedFn, false);
2108             return true;
2109
2110         },
2111
2112
2113         removeListener: function(el, eventName, fn) {
2114             var i, len;
2115
2116             el = Roo.getDom(el);
2117
2118             if(!fn) {
2119                 return this.purgeElement(el, false, eventName);
2120             }
2121
2122
2123             if ("unload" == eventName) {
2124
2125                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2126                     var li = unloadListeners[i];
2127                     if (li &&
2128                         li[0] == el &&
2129                         li[1] == eventName &&
2130                         li[2] == fn) {
2131                         unloadListeners.splice(i, 1);
2132                         return true;
2133                     }
2134                 }
2135
2136                 return false;
2137             }
2138
2139             var cacheItem = null;
2140
2141
2142             var index = arguments[3];
2143
2144             if ("undefined" == typeof index) {
2145                 index = this._getCacheIndex(el, eventName, fn);
2146             }
2147
2148             if (index >= 0) {
2149                 cacheItem = listeners[index];
2150             }
2151
2152             if (!el || !cacheItem) {
2153                 return false;
2154             }
2155
2156             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2157
2158             delete listeners[index][this.WFN];
2159             delete listeners[index][this.FN];
2160             listeners.splice(index, 1);
2161
2162             return true;
2163
2164         },
2165
2166
2167         getTarget: function(ev, resolveTextNode) {
2168             ev = ev.browserEvent || ev;
2169             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2170             var t = ev.target || ev.srcElement;
2171             return this.resolveTextNode(t);
2172         },
2173
2174
2175         resolveTextNode: function(node) {
2176             if (Roo.isSafari && node && 3 == node.nodeType) {
2177                 return node.parentNode;
2178             } else {
2179                 return node;
2180             }
2181         },
2182
2183
2184         getPageX: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             var x = ev.pageX;
2188             if (!x && 0 !== x) {
2189                 x = ev.clientX || 0;
2190
2191                 if (Roo.isIE) {
2192                     x += this.getScroll()[1];
2193                 }
2194             }
2195
2196             return x;
2197         },
2198
2199
2200         getPageY: function(ev) {
2201             ev = ev.browserEvent || ev;
2202             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2203             var y = ev.pageY;
2204             if (!y && 0 !== y) {
2205                 y = ev.clientY || 0;
2206
2207                 if (Roo.isIE) {
2208                     y += this.getScroll()[0];
2209                 }
2210             }
2211
2212
2213             return y;
2214         },
2215
2216
2217         getXY: function(ev) {
2218             ev = ev.browserEvent || ev;
2219             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2220             return [this.getPageX(ev), this.getPageY(ev)];
2221         },
2222
2223
2224         getRelatedTarget: function(ev) {
2225             ev = ev.browserEvent || ev;
2226             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2227             var t = ev.relatedTarget;
2228             if (!t) {
2229                 if (ev.type == "mouseout") {
2230                     t = ev.toElement;
2231                 } else if (ev.type == "mouseover") {
2232                     t = ev.fromElement;
2233                 }
2234             }
2235
2236             return this.resolveTextNode(t);
2237         },
2238
2239
2240         getTime: function(ev) {
2241             ev = ev.browserEvent || ev;
2242             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2243             if (!ev.time) {
2244                 var t = new Date().getTime();
2245                 try {
2246                     ev.time = t;
2247                 } catch(ex) {
2248                     this.lastError = ex;
2249                     return t;
2250                 }
2251             }
2252
2253             return ev.time;
2254         },
2255
2256
2257         stopEvent: function(ev) {
2258             this.stopPropagation(ev);
2259             this.preventDefault(ev);
2260         },
2261
2262
2263         stopPropagation: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             if (ev.stopPropagation) {
2266                 ev.stopPropagation();
2267             } else {
2268                 ev.cancelBubble = true;
2269             }
2270         },
2271
2272
2273         preventDefault: function(ev) {
2274             ev = ev.browserEvent || ev;
2275             if(ev.preventDefault) {
2276                 ev.preventDefault();
2277             } else {
2278                 ev.returnValue = false;
2279             }
2280         },
2281
2282
2283         getEvent: function(e) {
2284             var ev = e || window.event;
2285             if (!ev) {
2286                 var c = this.getEvent.caller;
2287                 while (c) {
2288                     ev = c.arguments[0];
2289                     if (ev && Event == ev.constructor) {
2290                         break;
2291                     }
2292                     c = c.caller;
2293                 }
2294             }
2295             return ev;
2296         },
2297
2298
2299         getCharCode: function(ev) {
2300             ev = ev.browserEvent || ev;
2301             return ev.charCode || ev.keyCode || 0;
2302         },
2303
2304
2305         _getCacheIndex: function(el, eventName, fn) {
2306             for (var i = 0,len = listeners.length; i < len; ++i) {
2307                 var li = listeners[i];
2308                 if (li &&
2309                     li[this.FN] == fn &&
2310                     li[this.EL] == el &&
2311                     li[this.TYPE] == eventName) {
2312                     return i;
2313                 }
2314             }
2315
2316             return -1;
2317         },
2318
2319
2320         elCache: {},
2321
2322
2323         getEl: function(id) {
2324             return document.getElementById(id);
2325         },
2326
2327
2328         clearCache: function() {
2329         },
2330
2331
2332         _load: function(e) {
2333             loadComplete = true;
2334             var EU = Roo.lib.Event;
2335
2336
2337             if (Roo.isIE) {
2338                 EU.doRemove(window, "load", EU._load);
2339             }
2340         },
2341
2342
2343         _tryPreloadAttach: function() {
2344
2345             if (this.locked) {
2346                 return false;
2347             }
2348
2349             this.locked = true;
2350
2351
2352             var tryAgain = !loadComplete;
2353             if (!tryAgain) {
2354                 tryAgain = (retryCount > 0);
2355             }
2356
2357
2358             var notAvail = [];
2359             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2360                 var item = onAvailStack[i];
2361                 if (item) {
2362                     var el = this.getEl(item.id);
2363
2364                     if (el) {
2365                         if (!item.checkReady ||
2366                             loadComplete ||
2367                             el.nextSibling ||
2368                             (document && document.body)) {
2369
2370                             var scope = el;
2371                             if (item.override) {
2372                                 if (item.override === true) {
2373                                     scope = item.obj;
2374                                 } else {
2375                                     scope = item.override;
2376                                 }
2377                             }
2378                             item.fn.call(scope, item.obj);
2379                             onAvailStack[i] = null;
2380                         }
2381                     } else {
2382                         notAvail.push(item);
2383                     }
2384                 }
2385             }
2386
2387             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2388
2389             if (tryAgain) {
2390
2391                 this.startInterval();
2392             } else {
2393                 clearInterval(this._interval);
2394                 this._interval = null;
2395             }
2396
2397             this.locked = false;
2398
2399             return true;
2400
2401         },
2402
2403
2404         purgeElement: function(el, recurse, eventName) {
2405             var elListeners = this.getListeners(el, eventName);
2406             if (elListeners) {
2407                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2408                     var l = elListeners[i];
2409                     this.removeListener(el, l.type, l.fn);
2410                 }
2411             }
2412
2413             if (recurse && el && el.childNodes) {
2414                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2415                     this.purgeElement(el.childNodes[i], recurse, eventName);
2416                 }
2417             }
2418         },
2419
2420
2421         getListeners: function(el, eventName) {
2422             var results = [], searchLists;
2423             if (!eventName) {
2424                 searchLists = [listeners, unloadListeners];
2425             } else if (eventName == "unload") {
2426                 searchLists = [unloadListeners];
2427             } else {
2428                 searchLists = [listeners];
2429             }
2430
2431             for (var j = 0; j < searchLists.length; ++j) {
2432                 var searchList = searchLists[j];
2433                 if (searchList && searchList.length > 0) {
2434                     for (var i = 0,len = searchList.length; i < len; ++i) {
2435                         var l = searchList[i];
2436                         if (l && l[this.EL] === el &&
2437                             (!eventName || eventName === l[this.TYPE])) {
2438                             results.push({
2439                                 type:   l[this.TYPE],
2440                                 fn:     l[this.FN],
2441                                 obj:    l[this.OBJ],
2442                                 adjust: l[this.ADJ_SCOPE],
2443                                 index:  i
2444                             });
2445                         }
2446                     }
2447                 }
2448             }
2449
2450             return (results.length) ? results : null;
2451         },
2452
2453
2454         _unload: function(e) {
2455
2456             var EU = Roo.lib.Event, i, j, l, len, index;
2457
2458             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2459                 l = unloadListeners[i];
2460                 if (l) {
2461                     var scope = window;
2462                     if (l[EU.ADJ_SCOPE]) {
2463                         if (l[EU.ADJ_SCOPE] === true) {
2464                             scope = l[EU.OBJ];
2465                         } else {
2466                             scope = l[EU.ADJ_SCOPE];
2467                         }
2468                     }
2469                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2470                     unloadListeners[i] = null;
2471                     l = null;
2472                     scope = null;
2473                 }
2474             }
2475
2476             unloadListeners = null;
2477
2478             if (listeners && listeners.length > 0) {
2479                 j = listeners.length;
2480                 while (j) {
2481                     index = j - 1;
2482                     l = listeners[index];
2483                     if (l) {
2484                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2485                                 l[EU.FN], index);
2486                     }
2487                     j = j - 1;
2488                 }
2489                 l = null;
2490
2491                 EU.clearCache();
2492             }
2493
2494             EU.doRemove(window, "unload", EU._unload);
2495
2496         },
2497
2498
2499         getScroll: function() {
2500             var dd = document.documentElement, db = document.body;
2501             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2502                 return [dd.scrollTop, dd.scrollLeft];
2503             } else if (db) {
2504                 return [db.scrollTop, db.scrollLeft];
2505             } else {
2506                 return [0, 0];
2507             }
2508         },
2509
2510
2511         doAdd: function () {
2512             if (window.addEventListener) {
2513                 return function(el, eventName, fn, capture) {
2514                     el.addEventListener(eventName, fn, (capture));
2515                 };
2516             } else if (window.attachEvent) {
2517                 return function(el, eventName, fn, capture) {
2518                     el.attachEvent("on" + eventName, fn);
2519                 };
2520             } else {
2521                 return function() {
2522                 };
2523             }
2524         }(),
2525
2526
2527         doRemove: function() {
2528             if (window.removeEventListener) {
2529                 return function (el, eventName, fn, capture) {
2530                     el.removeEventListener(eventName, fn, (capture));
2531                 };
2532             } else if (window.detachEvent) {
2533                 return function (el, eventName, fn) {
2534                     el.detachEvent("on" + eventName, fn);
2535                 };
2536             } else {
2537                 return function() {
2538                 };
2539             }
2540         }()
2541     };
2542     
2543 }();
2544 (function() {     
2545    
2546     var E = Roo.lib.Event;
2547     E.on = E.addListener;
2548     E.un = E.removeListener;
2549
2550     if (document && document.body) {
2551         E._load();
2552     } else {
2553         E.doAdd(window, "load", E._load);
2554     }
2555     E.doAdd(window, "unload", E._unload);
2556     E._tryPreloadAttach();
2557 })();
2558
2559 /*
2560  * Portions of this file are based on pieces of Yahoo User Interface Library
2561  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2562  * YUI licensed under the BSD License:
2563  * http://developer.yahoo.net/yui/license.txt
2564  * <script type="text/javascript">
2565  *
2566  */
2567
2568 (function() {
2569     /**
2570      * @class Roo.lib.Ajax
2571      *
2572      */
2573     Roo.lib.Ajax = {
2574         /**
2575          * @static 
2576          */
2577         request : function(method, uri, cb, data, options) {
2578             if(options){
2579                 var hs = options.headers;
2580                 if(hs){
2581                     for(var h in hs){
2582                         if(hs.hasOwnProperty(h)){
2583                             this.initHeader(h, hs[h], false);
2584                         }
2585                     }
2586                 }
2587                 if(options.xmlData){
2588                     this.initHeader('Content-Type', 'text/xml', false);
2589                     method = 'POST';
2590                     data = options.xmlData;
2591                 }
2592             }
2593
2594             return this.asyncRequest(method, uri, cb, data);
2595         },
2596
2597         serializeForm : function(form) {
2598             if(typeof form == 'string') {
2599                 form = (document.getElementById(form) || document.forms[form]);
2600             }
2601
2602             var el, name, val, disabled, data = '', hasSubmit = false;
2603             for (var i = 0; i < form.elements.length; i++) {
2604                 el = form.elements[i];
2605                 disabled = form.elements[i].disabled;
2606                 name = form.elements[i].name;
2607                 val = form.elements[i].value;
2608
2609                 if (!disabled && name){
2610                     switch (el.type)
2611                             {
2612                         case 'select-one':
2613                         case 'select-multiple':
2614                             for (var j = 0; j < el.options.length; j++) {
2615                                 if (el.options[j].selected) {
2616                                     if (Roo.isIE) {
2617                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2618                                     }
2619                                     else {
2620                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2621                                     }
2622                                 }
2623                             }
2624                             break;
2625                         case 'radio':
2626                         case 'checkbox':
2627                             if (el.checked) {
2628                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2629                             }
2630                             break;
2631                         case 'file':
2632
2633                         case undefined:
2634
2635                         case 'reset':
2636
2637                         case 'button':
2638
2639                             break;
2640                         case 'submit':
2641                             if(hasSubmit == false) {
2642                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2643                                 hasSubmit = true;
2644                             }
2645                             break;
2646                         default:
2647                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2648                             break;
2649                     }
2650                 }
2651             }
2652             data = data.substr(0, data.length - 1);
2653             return data;
2654         },
2655
2656         headers:{},
2657
2658         hasHeaders:false,
2659
2660         useDefaultHeader:true,
2661
2662         defaultPostHeader:'application/x-www-form-urlencoded',
2663
2664         useDefaultXhrHeader:true,
2665
2666         defaultXhrHeader:'XMLHttpRequest',
2667
2668         hasDefaultHeaders:true,
2669
2670         defaultHeaders:{},
2671
2672         poll:{},
2673
2674         timeout:{},
2675
2676         pollInterval:50,
2677
2678         transactionId:0,
2679
2680         setProgId:function(id)
2681         {
2682             this.activeX.unshift(id);
2683         },
2684
2685         setDefaultPostHeader:function(b)
2686         {
2687             this.useDefaultHeader = b;
2688         },
2689
2690         setDefaultXhrHeader:function(b)
2691         {
2692             this.useDefaultXhrHeader = b;
2693         },
2694
2695         setPollingInterval:function(i)
2696         {
2697             if (typeof i == 'number' && isFinite(i)) {
2698                 this.pollInterval = i;
2699             }
2700         },
2701
2702         createXhrObject:function(transactionId)
2703         {
2704             var obj,http;
2705             try
2706             {
2707
2708                 http = new XMLHttpRequest();
2709
2710                 obj = { conn:http, tId:transactionId };
2711             }
2712             catch(e)
2713             {
2714                 for (var i = 0; i < this.activeX.length; ++i) {
2715                     try
2716                     {
2717
2718                         http = new ActiveXObject(this.activeX[i]);
2719
2720                         obj = { conn:http, tId:transactionId };
2721                         break;
2722                     }
2723                     catch(e) {
2724                     }
2725                 }
2726             }
2727             finally
2728             {
2729                 return obj;
2730             }
2731         },
2732
2733         getConnectionObject:function()
2734         {
2735             var o;
2736             var tId = this.transactionId;
2737
2738             try
2739             {
2740                 o = this.createXhrObject(tId);
2741                 if (o) {
2742                     this.transactionId++;
2743                 }
2744             }
2745             catch(e) {
2746             }
2747             finally
2748             {
2749                 return o;
2750             }
2751         },
2752
2753         asyncRequest:function(method, uri, callback, postData)
2754         {
2755             var o = this.getConnectionObject();
2756
2757             if (!o) {
2758                 return null;
2759             }
2760             else {
2761                 o.conn.open(method, uri, true);
2762
2763                 if (this.useDefaultXhrHeader) {
2764                     if (!this.defaultHeaders['X-Requested-With']) {
2765                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2766                     }
2767                 }
2768
2769                 if(postData && this.useDefaultHeader){
2770                     this.initHeader('Content-Type', this.defaultPostHeader);
2771                 }
2772
2773                  if (this.hasDefaultHeaders || this.hasHeaders) {
2774                     this.setHeader(o);
2775                 }
2776
2777                 this.handleReadyState(o, callback);
2778                 o.conn.send(postData || null);
2779
2780                 return o;
2781             }
2782         },
2783
2784         handleReadyState:function(o, callback)
2785         {
2786             var oConn = this;
2787
2788             if (callback && callback.timeout) {
2789                 
2790                 this.timeout[o.tId] = window.setTimeout(function() {
2791                     oConn.abort(o, callback, true);
2792                 }, callback.timeout);
2793             }
2794
2795             this.poll[o.tId] = window.setInterval(
2796                     function() {
2797                         if (o.conn && o.conn.readyState == 4) {
2798                             window.clearInterval(oConn.poll[o.tId]);
2799                             delete oConn.poll[o.tId];
2800
2801                             if(callback && callback.timeout) {
2802                                 window.clearTimeout(oConn.timeout[o.tId]);
2803                                 delete oConn.timeout[o.tId];
2804                             }
2805
2806                             oConn.handleTransactionResponse(o, callback);
2807                         }
2808                     }
2809                     , this.pollInterval);
2810         },
2811
2812         handleTransactionResponse:function(o, callback, isAbort)
2813         {
2814
2815             if (!callback) {
2816                 this.releaseObject(o);
2817                 return;
2818             }
2819
2820             var httpStatus, responseObject;
2821
2822             try
2823             {
2824                 if (o.conn.status !== undefined && o.conn.status != 0) {
2825                     httpStatus = o.conn.status;
2826                 }
2827                 else {
2828                     httpStatus = 13030;
2829                 }
2830             }
2831             catch(e) {
2832
2833
2834                 httpStatus = 13030;
2835             }
2836
2837             if (httpStatus >= 200 && httpStatus < 300) {
2838                 responseObject = this.createResponseObject(o, callback.argument);
2839                 if (callback.success) {
2840                     if (!callback.scope) {
2841                         callback.success(responseObject);
2842                     }
2843                     else {
2844
2845
2846                         callback.success.apply(callback.scope, [responseObject]);
2847                     }
2848                 }
2849             }
2850             else {
2851                 switch (httpStatus) {
2852
2853                     case 12002:
2854                     case 12029:
2855                     case 12030:
2856                     case 12031:
2857                     case 12152:
2858                     case 13030:
2859                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2860                         if (callback.failure) {
2861                             if (!callback.scope) {
2862                                 callback.failure(responseObject);
2863                             }
2864                             else {
2865                                 callback.failure.apply(callback.scope, [responseObject]);
2866                             }
2867                         }
2868                         break;
2869                     default:
2870                         responseObject = this.createResponseObject(o, callback.argument);
2871                         if (callback.failure) {
2872                             if (!callback.scope) {
2873                                 callback.failure(responseObject);
2874                             }
2875                             else {
2876                                 callback.failure.apply(callback.scope, [responseObject]);
2877                             }
2878                         }
2879                 }
2880             }
2881
2882             this.releaseObject(o);
2883             responseObject = null;
2884         },
2885
2886         createResponseObject:function(o, callbackArg)
2887         {
2888             var obj = {};
2889             var headerObj = {};
2890
2891             try
2892             {
2893                 var headerStr = o.conn.getAllResponseHeaders();
2894                 var header = headerStr.split('\n');
2895                 for (var i = 0; i < header.length; i++) {
2896                     var delimitPos = header[i].indexOf(':');
2897                     if (delimitPos != -1) {
2898                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2899                     }
2900                 }
2901             }
2902             catch(e) {
2903             }
2904
2905             obj.tId = o.tId;
2906             obj.status = o.conn.status;
2907             obj.statusText = o.conn.statusText;
2908             obj.getResponseHeader = headerObj;
2909             obj.getAllResponseHeaders = headerStr;
2910             obj.responseText = o.conn.responseText;
2911             obj.responseXML = o.conn.responseXML;
2912
2913             if (typeof callbackArg !== undefined) {
2914                 obj.argument = callbackArg;
2915             }
2916
2917             return obj;
2918         },
2919
2920         createExceptionObject:function(tId, callbackArg, isAbort)
2921         {
2922             var COMM_CODE = 0;
2923             var COMM_ERROR = 'communication failure';
2924             var ABORT_CODE = -1;
2925             var ABORT_ERROR = 'transaction aborted';
2926
2927             var obj = {};
2928
2929             obj.tId = tId;
2930             if (isAbort) {
2931                 obj.status = ABORT_CODE;
2932                 obj.statusText = ABORT_ERROR;
2933             }
2934             else {
2935                 obj.status = COMM_CODE;
2936                 obj.statusText = COMM_ERROR;
2937             }
2938
2939             if (callbackArg) {
2940                 obj.argument = callbackArg;
2941             }
2942
2943             return obj;
2944         },
2945
2946         initHeader:function(label, value, isDefault)
2947         {
2948             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2949
2950             if (headerObj[label] === undefined) {
2951                 headerObj[label] = value;
2952             }
2953             else {
2954
2955
2956                 headerObj[label] = value + "," + headerObj[label];
2957             }
2958
2959             if (isDefault) {
2960                 this.hasDefaultHeaders = true;
2961             }
2962             else {
2963                 this.hasHeaders = true;
2964             }
2965         },
2966
2967
2968         setHeader:function(o)
2969         {
2970             if (this.hasDefaultHeaders) {
2971                 for (var prop in this.defaultHeaders) {
2972                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2973                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2974                     }
2975                 }
2976             }
2977
2978             if (this.hasHeaders) {
2979                 for (var prop in this.headers) {
2980                     if (this.headers.hasOwnProperty(prop)) {
2981                         o.conn.setRequestHeader(prop, this.headers[prop]);
2982                     }
2983                 }
2984                 this.headers = {};
2985                 this.hasHeaders = false;
2986             }
2987         },
2988
2989         resetDefaultHeaders:function() {
2990             delete this.defaultHeaders;
2991             this.defaultHeaders = {};
2992             this.hasDefaultHeaders = false;
2993         },
2994
2995         abort:function(o, callback, isTimeout)
2996         {
2997             if(this.isCallInProgress(o)) {
2998                 o.conn.abort();
2999                 window.clearInterval(this.poll[o.tId]);
3000                 delete this.poll[o.tId];
3001                 if (isTimeout) {
3002                     delete this.timeout[o.tId];
3003                 }
3004
3005                 this.handleTransactionResponse(o, callback, true);
3006
3007                 return true;
3008             }
3009             else {
3010                 return false;
3011             }
3012         },
3013
3014
3015         isCallInProgress:function(o)
3016         {
3017             if (o && o.conn) {
3018                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3019             }
3020             else {
3021
3022                 return false;
3023             }
3024         },
3025
3026
3027         releaseObject:function(o)
3028         {
3029
3030             o.conn = null;
3031
3032             o = null;
3033         },
3034
3035         activeX:[
3036         'MSXML2.XMLHTTP.3.0',
3037         'MSXML2.XMLHTTP',
3038         'Microsoft.XMLHTTP'
3039         ]
3040
3041
3042     };
3043 })();/*
3044  * Portions of this file are based on pieces of Yahoo User Interface Library
3045  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046  * YUI licensed under the BSD License:
3047  * http://developer.yahoo.net/yui/license.txt
3048  * <script type="text/javascript">
3049  *
3050  */
3051
3052 Roo.lib.Region = function(t, r, b, l) {
3053     this.top = t;
3054     this[1] = t;
3055     this.right = r;
3056     this.bottom = b;
3057     this.left = l;
3058     this[0] = l;
3059 };
3060
3061
3062 Roo.lib.Region.prototype = {
3063     contains : function(region) {
3064         return ( region.left >= this.left &&
3065                  region.right <= this.right &&
3066                  region.top >= this.top &&
3067                  region.bottom <= this.bottom    );
3068
3069     },
3070
3071     getArea : function() {
3072         return ( (this.bottom - this.top) * (this.right - this.left) );
3073     },
3074
3075     intersect : function(region) {
3076         var t = Math.max(this.top, region.top);
3077         var r = Math.min(this.right, region.right);
3078         var b = Math.min(this.bottom, region.bottom);
3079         var l = Math.max(this.left, region.left);
3080
3081         if (b >= t && r >= l) {
3082             return new Roo.lib.Region(t, r, b, l);
3083         } else {
3084             return null;
3085         }
3086     },
3087     union : function(region) {
3088         var t = Math.min(this.top, region.top);
3089         var r = Math.max(this.right, region.right);
3090         var b = Math.max(this.bottom, region.bottom);
3091         var l = Math.min(this.left, region.left);
3092
3093         return new Roo.lib.Region(t, r, b, l);
3094     },
3095
3096     adjust : function(t, l, b, r) {
3097         this.top += t;
3098         this.left += l;
3099         this.right += r;
3100         this.bottom += b;
3101         return this;
3102     }
3103 };
3104
3105 Roo.lib.Region.getRegion = function(el) {
3106     var p = Roo.lib.Dom.getXY(el);
3107
3108     var t = p[1];
3109     var r = p[0] + el.offsetWidth;
3110     var b = p[1] + el.offsetHeight;
3111     var l = p[0];
3112
3113     return new Roo.lib.Region(t, r, b, l);
3114 };
3115 /*
3116  * Portions of this file are based on pieces of Yahoo User Interface Library
3117  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3118  * YUI licensed under the BSD License:
3119  * http://developer.yahoo.net/yui/license.txt
3120  * <script type="text/javascript">
3121  *
3122  */
3123 //@@dep Roo.lib.Region
3124
3125
3126 Roo.lib.Point = function(x, y) {
3127     if (x instanceof Array) {
3128         y = x[1];
3129         x = x[0];
3130     }
3131     this.x = this.right = this.left = this[0] = x;
3132     this.y = this.top = this.bottom = this[1] = y;
3133 };
3134
3135 Roo.lib.Point.prototype = new Roo.lib.Region();
3136 /*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144  
3145 (function() {   
3146
3147     Roo.lib.Anim = {
3148         scroll : function(el, args, duration, easing, cb, scope) {
3149             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3150         },
3151
3152         motion : function(el, args, duration, easing, cb, scope) {
3153             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3154         },
3155
3156         color : function(el, args, duration, easing, cb, scope) {
3157             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3158         },
3159
3160         run : function(el, args, duration, easing, cb, scope, type) {
3161             type = type || Roo.lib.AnimBase;
3162             if (typeof easing == "string") {
3163                 easing = Roo.lib.Easing[easing];
3164             }
3165             var anim = new type(el, args, duration, easing);
3166             anim.animateX(function() {
3167                 Roo.callback(cb, scope);
3168             });
3169             return anim;
3170         }
3171     };
3172 })();/*
3173  * Portions of this file are based on pieces of Yahoo User Interface Library
3174  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3175  * YUI licensed under the BSD License:
3176  * http://developer.yahoo.net/yui/license.txt
3177  * <script type="text/javascript">
3178  *
3179  */
3180
3181 (function() {    
3182     var libFlyweight;
3183     
3184     function fly(el) {
3185         if (!libFlyweight) {
3186             libFlyweight = new Roo.Element.Flyweight();
3187         }
3188         libFlyweight.dom = el;
3189         return libFlyweight;
3190     }
3191
3192     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3193     
3194    
3195     
3196     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3197         if (el) {
3198             this.init(el, attributes, duration, method);
3199         }
3200     };
3201
3202     Roo.lib.AnimBase.fly = fly;
3203     
3204     
3205     
3206     Roo.lib.AnimBase.prototype = {
3207
3208         toString: function() {
3209             var el = this.getEl();
3210             var id = el.id || el.tagName;
3211             return ("Anim " + id);
3212         },
3213
3214         patterns: {
3215             noNegatives:        /width|height|opacity|padding/i,
3216             offsetAttribute:  /^((width|height)|(top|left))$/,
3217             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3218             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3219         },
3220
3221
3222         doMethod: function(attr, start, end) {
3223             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3224         },
3225
3226
3227         setAttribute: function(attr, val, unit) {
3228             if (this.patterns.noNegatives.test(attr)) {
3229                 val = (val > 0) ? val : 0;
3230             }
3231
3232             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3233         },
3234
3235
3236         getAttribute: function(attr) {
3237             var el = this.getEl();
3238             var val = fly(el).getStyle(attr);
3239
3240             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3241                 return parseFloat(val);
3242             }
3243
3244             var a = this.patterns.offsetAttribute.exec(attr) || [];
3245             var pos = !!( a[3] );
3246             var box = !!( a[2] );
3247
3248
3249             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3250                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3251             } else {
3252                 val = 0;
3253             }
3254
3255             return val;
3256         },
3257
3258
3259         getDefaultUnit: function(attr) {
3260             if (this.patterns.defaultUnit.test(attr)) {
3261                 return 'px';
3262             }
3263
3264             return '';
3265         },
3266
3267         animateX : function(callback, scope) {
3268             var f = function() {
3269                 this.onComplete.removeListener(f);
3270                 if (typeof callback == "function") {
3271                     callback.call(scope || this, this);
3272                 }
3273             };
3274             this.onComplete.addListener(f, this);
3275             this.animate();
3276         },
3277
3278
3279         setRuntimeAttribute: function(attr) {
3280             var start;
3281             var end;
3282             var attributes = this.attributes;
3283
3284             this.runtimeAttributes[attr] = {};
3285
3286             var isset = function(prop) {
3287                 return (typeof prop !== 'undefined');
3288             };
3289
3290             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3291                 return false;
3292             }
3293
3294             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3295
3296
3297             if (isset(attributes[attr]['to'])) {
3298                 end = attributes[attr]['to'];
3299             } else if (isset(attributes[attr]['by'])) {
3300                 if (start.constructor == Array) {
3301                     end = [];
3302                     for (var i = 0, len = start.length; i < len; ++i) {
3303                         end[i] = start[i] + attributes[attr]['by'][i];
3304                     }
3305                 } else {
3306                     end = start + attributes[attr]['by'];
3307                 }
3308             }
3309
3310             this.runtimeAttributes[attr].start = start;
3311             this.runtimeAttributes[attr].end = end;
3312
3313
3314             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3315         },
3316
3317
3318         init: function(el, attributes, duration, method) {
3319
3320             var isAnimated = false;
3321
3322
3323             var startTime = null;
3324
3325
3326             var actualFrames = 0;
3327
3328
3329             el = Roo.getDom(el);
3330
3331
3332             this.attributes = attributes || {};
3333
3334
3335             this.duration = duration || 1;
3336
3337
3338             this.method = method || Roo.lib.Easing.easeNone;
3339
3340
3341             this.useSeconds = true;
3342
3343
3344             this.currentFrame = 0;
3345
3346
3347             this.totalFrames = Roo.lib.AnimMgr.fps;
3348
3349
3350             this.getEl = function() {
3351                 return el;
3352             };
3353
3354
3355             this.isAnimated = function() {
3356                 return isAnimated;
3357             };
3358
3359
3360             this.getStartTime = function() {
3361                 return startTime;
3362             };
3363
3364             this.runtimeAttributes = {};
3365
3366
3367             this.animate = function() {
3368                 if (this.isAnimated()) {
3369                     return false;
3370                 }
3371
3372                 this.currentFrame = 0;
3373
3374                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3375
3376                 Roo.lib.AnimMgr.registerElement(this);
3377             };
3378
3379
3380             this.stop = function(finish) {
3381                 if (finish) {
3382                     this.currentFrame = this.totalFrames;
3383                     this._onTween.fire();
3384                 }
3385                 Roo.lib.AnimMgr.stop(this);
3386             };
3387
3388             var onStart = function() {
3389                 this.onStart.fire();
3390
3391                 this.runtimeAttributes = {};
3392                 for (var attr in this.attributes) {
3393                     this.setRuntimeAttribute(attr);
3394                 }
3395
3396                 isAnimated = true;
3397                 actualFrames = 0;
3398                 startTime = new Date();
3399             };
3400
3401
3402             var onTween = function() {
3403                 var data = {
3404                     duration: new Date() - this.getStartTime(),
3405                     currentFrame: this.currentFrame
3406                 };
3407
3408                 data.toString = function() {
3409                     return (
3410                             'duration: ' + data.duration +
3411                             ', currentFrame: ' + data.currentFrame
3412                             );
3413                 };
3414
3415                 this.onTween.fire(data);
3416
3417                 var runtimeAttributes = this.runtimeAttributes;
3418
3419                 for (var attr in runtimeAttributes) {
3420                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3421                 }
3422
3423                 actualFrames += 1;
3424             };
3425
3426             var onComplete = function() {
3427                 var actual_duration = (new Date() - startTime) / 1000 ;
3428
3429                 var data = {
3430                     duration: actual_duration,
3431                     frames: actualFrames,
3432                     fps: actualFrames / actual_duration
3433                 };
3434
3435                 data.toString = function() {
3436                     return (
3437                             'duration: ' + data.duration +
3438                             ', frames: ' + data.frames +
3439                             ', fps: ' + data.fps
3440                             );
3441                 };
3442
3443                 isAnimated = false;
3444                 actualFrames = 0;
3445                 this.onComplete.fire(data);
3446             };
3447
3448
3449             this._onStart = new Roo.util.Event(this);
3450             this.onStart = new Roo.util.Event(this);
3451             this.onTween = new Roo.util.Event(this);
3452             this._onTween = new Roo.util.Event(this);
3453             this.onComplete = new Roo.util.Event(this);
3454             this._onComplete = new Roo.util.Event(this);
3455             this._onStart.addListener(onStart);
3456             this._onTween.addListener(onTween);
3457             this._onComplete.addListener(onComplete);
3458         }
3459     };
3460 })();
3461 /*
3462  * Portions of this file are based on pieces of Yahoo User Interface Library
3463  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3464  * YUI licensed under the BSD License:
3465  * http://developer.yahoo.net/yui/license.txt
3466  * <script type="text/javascript">
3467  *
3468  */
3469
3470 Roo.lib.AnimMgr = new function() {
3471
3472     var thread = null;
3473
3474
3475     var queue = [];
3476
3477
3478     var tweenCount = 0;
3479
3480
3481     this.fps = 1000;
3482
3483
3484     this.delay = 1;
3485
3486
3487     this.registerElement = function(tween) {
3488         queue[queue.length] = tween;
3489         tweenCount += 1;
3490         tween._onStart.fire();
3491         this.start();
3492     };
3493
3494
3495     this.unRegister = function(tween, index) {
3496         tween._onComplete.fire();
3497         index = index || getIndex(tween);
3498         if (index != -1) {
3499             queue.splice(index, 1);
3500         }
3501
3502         tweenCount -= 1;
3503         if (tweenCount <= 0) {
3504             this.stop();
3505         }
3506     };
3507
3508
3509     this.start = function() {
3510         if (thread === null) {
3511             thread = setInterval(this.run, this.delay);
3512         }
3513     };
3514
3515
3516     this.stop = function(tween) {
3517         if (!tween) {
3518             clearInterval(thread);
3519
3520             for (var i = 0, len = queue.length; i < len; ++i) {
3521                 if (queue[0].isAnimated()) {
3522                     this.unRegister(queue[0], 0);
3523                 }
3524             }
3525
3526             queue = [];
3527             thread = null;
3528             tweenCount = 0;
3529         }
3530         else {
3531             this.unRegister(tween);
3532         }
3533     };
3534
3535
3536     this.run = function() {
3537         for (var i = 0, len = queue.length; i < len; ++i) {
3538             var tween = queue[i];
3539             if (!tween || !tween.isAnimated()) {
3540                 continue;
3541             }
3542
3543             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3544             {
3545                 tween.currentFrame += 1;
3546
3547                 if (tween.useSeconds) {
3548                     correctFrame(tween);
3549                 }
3550                 tween._onTween.fire();
3551             }
3552             else {
3553                 Roo.lib.AnimMgr.stop(tween, i);
3554             }
3555         }
3556     };
3557
3558     var getIndex = function(anim) {
3559         for (var i = 0, len = queue.length; i < len; ++i) {
3560             if (queue[i] == anim) {
3561                 return i;
3562             }
3563         }
3564         return -1;
3565     };
3566
3567
3568     var correctFrame = function(tween) {
3569         var frames = tween.totalFrames;
3570         var frame = tween.currentFrame;
3571         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3572         var elapsed = (new Date() - tween.getStartTime());
3573         var tweak = 0;
3574
3575         if (elapsed < tween.duration * 1000) {
3576             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3577         } else {
3578             tweak = frames - (frame + 1);
3579         }
3580         if (tweak > 0 && isFinite(tweak)) {
3581             if (tween.currentFrame + tweak >= frames) {
3582                 tweak = frames - (frame + 1);
3583             }
3584
3585             tween.currentFrame += tweak;
3586         }
3587     };
3588 };
3589
3590     /*
3591  * Portions of this file are based on pieces of Yahoo User Interface Library
3592  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3593  * YUI licensed under the BSD License:
3594  * http://developer.yahoo.net/yui/license.txt
3595  * <script type="text/javascript">
3596  *
3597  */
3598 Roo.lib.Bezier = new function() {
3599
3600         this.getPosition = function(points, t) {
3601             var n = points.length;
3602             var tmp = [];
3603
3604             for (var i = 0; i < n; ++i) {
3605                 tmp[i] = [points[i][0], points[i][1]];
3606             }
3607
3608             for (var j = 1; j < n; ++j) {
3609                 for (i = 0; i < n - j; ++i) {
3610                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3611                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3612                 }
3613             }
3614
3615             return [ tmp[0][0], tmp[0][1] ];
3616
3617         };
3618     };/*
3619  * Portions of this file are based on pieces of Yahoo User Interface Library
3620  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3621  * YUI licensed under the BSD License:
3622  * http://developer.yahoo.net/yui/license.txt
3623  * <script type="text/javascript">
3624  *
3625  */
3626 (function() {
3627
3628     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3629         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3630     };
3631
3632     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3633
3634     var fly = Roo.lib.AnimBase.fly;
3635     var Y = Roo.lib;
3636     var superclass = Y.ColorAnim.superclass;
3637     var proto = Y.ColorAnim.prototype;
3638
3639     proto.toString = function() {
3640         var el = this.getEl();
3641         var id = el.id || el.tagName;
3642         return ("ColorAnim " + id);
3643     };
3644
3645     proto.patterns.color = /color$/i;
3646     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3647     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3648     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3649     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3650
3651
3652     proto.parseColor = function(s) {
3653         if (s.length == 3) {
3654             return s;
3655         }
3656
3657         var c = this.patterns.hex.exec(s);
3658         if (c && c.length == 4) {
3659             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3660         }
3661
3662         c = this.patterns.rgb.exec(s);
3663         if (c && c.length == 4) {
3664             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3665         }
3666
3667         c = this.patterns.hex3.exec(s);
3668         if (c && c.length == 4) {
3669             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3670         }
3671
3672         return null;
3673     };
3674     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3675     proto.getAttribute = function(attr) {
3676         var el = this.getEl();
3677         if (this.patterns.color.test(attr)) {
3678             var val = fly(el).getStyle(attr);
3679
3680             if (this.patterns.transparent.test(val)) {
3681                 var parent = el.parentNode;
3682                 val = fly(parent).getStyle(attr);
3683
3684                 while (parent && this.patterns.transparent.test(val)) {
3685                     parent = parent.parentNode;
3686                     val = fly(parent).getStyle(attr);
3687                     if (parent.tagName.toUpperCase() == 'HTML') {
3688                         val = '#fff';
3689                     }
3690                 }
3691             }
3692         } else {
3693             val = superclass.getAttribute.call(this, attr);
3694         }
3695
3696         return val;
3697     };
3698     proto.getAttribute = function(attr) {
3699         var el = this.getEl();
3700         if (this.patterns.color.test(attr)) {
3701             var val = fly(el).getStyle(attr);
3702
3703             if (this.patterns.transparent.test(val)) {
3704                 var parent = el.parentNode;
3705                 val = fly(parent).getStyle(attr);
3706
3707                 while (parent && this.patterns.transparent.test(val)) {
3708                     parent = parent.parentNode;
3709                     val = fly(parent).getStyle(attr);
3710                     if (parent.tagName.toUpperCase() == 'HTML') {
3711                         val = '#fff';
3712                     }
3713                 }
3714             }
3715         } else {
3716             val = superclass.getAttribute.call(this, attr);
3717         }
3718
3719         return val;
3720     };
3721
3722     proto.doMethod = function(attr, start, end) {
3723         var val;
3724
3725         if (this.patterns.color.test(attr)) {
3726             val = [];
3727             for (var i = 0, len = start.length; i < len; ++i) {
3728                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3729             }
3730
3731             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3732         }
3733         else {
3734             val = superclass.doMethod.call(this, attr, start, end);
3735         }
3736
3737         return val;
3738     };
3739
3740     proto.setRuntimeAttribute = function(attr) {
3741         superclass.setRuntimeAttribute.call(this, attr);
3742
3743         if (this.patterns.color.test(attr)) {
3744             var attributes = this.attributes;
3745             var start = this.parseColor(this.runtimeAttributes[attr].start);
3746             var end = this.parseColor(this.runtimeAttributes[attr].end);
3747
3748             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3749                 end = this.parseColor(attributes[attr].by);
3750
3751                 for (var i = 0, len = start.length; i < len; ++i) {
3752                     end[i] = start[i] + end[i];
3753                 }
3754             }
3755
3756             this.runtimeAttributes[attr].start = start;
3757             this.runtimeAttributes[attr].end = end;
3758         }
3759     };
3760 })();
3761
3762 /*
3763  * Portions of this file are based on pieces of Yahoo User Interface Library
3764  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3765  * YUI licensed under the BSD License:
3766  * http://developer.yahoo.net/yui/license.txt
3767  * <script type="text/javascript">
3768  *
3769  */
3770 Roo.lib.Easing = {
3771
3772
3773     easeNone: function (t, b, c, d) {
3774         return c * t / d + b;
3775     },
3776
3777
3778     easeIn: function (t, b, c, d) {
3779         return c * (t /= d) * t + b;
3780     },
3781
3782
3783     easeOut: function (t, b, c, d) {
3784         return -c * (t /= d) * (t - 2) + b;
3785     },
3786
3787
3788     easeBoth: function (t, b, c, d) {
3789         if ((t /= d / 2) < 1) {
3790             return c / 2 * t * t + b;
3791         }
3792
3793         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3794     },
3795
3796
3797     easeInStrong: function (t, b, c, d) {
3798         return c * (t /= d) * t * t * t + b;
3799     },
3800
3801
3802     easeOutStrong: function (t, b, c, d) {
3803         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3804     },
3805
3806
3807     easeBothStrong: function (t, b, c, d) {
3808         if ((t /= d / 2) < 1) {
3809             return c / 2 * t * t * t * t + b;
3810         }
3811
3812         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3813     },
3814
3815
3816
3817     elasticIn: function (t, b, c, d, a, p) {
3818         if (t == 0) {
3819             return b;
3820         }
3821         if ((t /= d) == 1) {
3822             return b + c;
3823         }
3824         if (!p) {
3825             p = d * .3;
3826         }
3827
3828         if (!a || a < Math.abs(c)) {
3829             a = c;
3830             var s = p / 4;
3831         }
3832         else {
3833             var s = p / (2 * Math.PI) * Math.asin(c / a);
3834         }
3835
3836         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3837     },
3838
3839
3840     elasticOut: function (t, b, c, d, a, p) {
3841         if (t == 0) {
3842             return b;
3843         }
3844         if ((t /= d) == 1) {
3845             return b + c;
3846         }
3847         if (!p) {
3848             p = d * .3;
3849         }
3850
3851         if (!a || a < Math.abs(c)) {
3852             a = c;
3853             var s = p / 4;
3854         }
3855         else {
3856             var s = p / (2 * Math.PI) * Math.asin(c / a);
3857         }
3858
3859         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3860     },
3861
3862
3863     elasticBoth: function (t, b, c, d, a, p) {
3864         if (t == 0) {
3865             return b;
3866         }
3867
3868         if ((t /= d / 2) == 2) {
3869             return b + c;
3870         }
3871
3872         if (!p) {
3873             p = d * (.3 * 1.5);
3874         }
3875
3876         if (!a || a < Math.abs(c)) {
3877             a = c;
3878             var s = p / 4;
3879         }
3880         else {
3881             var s = p / (2 * Math.PI) * Math.asin(c / a);
3882         }
3883
3884         if (t < 1) {
3885             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3886                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3887         }
3888         return a * Math.pow(2, -10 * (t -= 1)) *
3889                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3890     },
3891
3892
3893
3894     backIn: function (t, b, c, d, s) {
3895         if (typeof s == 'undefined') {
3896             s = 1.70158;
3897         }
3898         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3899     },
3900
3901
3902     backOut: function (t, b, c, d, s) {
3903         if (typeof s == 'undefined') {
3904             s = 1.70158;
3905         }
3906         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3907     },
3908
3909
3910     backBoth: function (t, b, c, d, s) {
3911         if (typeof s == 'undefined') {
3912             s = 1.70158;
3913         }
3914
3915         if ((t /= d / 2 ) < 1) {
3916             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3917         }
3918         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3919     },
3920
3921
3922     bounceIn: function (t, b, c, d) {
3923         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3924     },
3925
3926
3927     bounceOut: function (t, b, c, d) {
3928         if ((t /= d) < (1 / 2.75)) {
3929             return c * (7.5625 * t * t) + b;
3930         } else if (t < (2 / 2.75)) {
3931             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3932         } else if (t < (2.5 / 2.75)) {
3933             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3934         }
3935         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3936     },
3937
3938
3939     bounceBoth: function (t, b, c, d) {
3940         if (t < d / 2) {
3941             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3942         }
3943         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3944     }
3945 };/*
3946  * Portions of this file are based on pieces of Yahoo User Interface Library
3947  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3948  * YUI licensed under the BSD License:
3949  * http://developer.yahoo.net/yui/license.txt
3950  * <script type="text/javascript">
3951  *
3952  */
3953     (function() {
3954         Roo.lib.Motion = function(el, attributes, duration, method) {
3955             if (el) {
3956                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3957             }
3958         };
3959
3960         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3961
3962
3963         var Y = Roo.lib;
3964         var superclass = Y.Motion.superclass;
3965         var proto = Y.Motion.prototype;
3966
3967         proto.toString = function() {
3968             var el = this.getEl();
3969             var id = el.id || el.tagName;
3970             return ("Motion " + id);
3971         };
3972
3973         proto.patterns.points = /^points$/i;
3974
3975         proto.setAttribute = function(attr, val, unit) {
3976             if (this.patterns.points.test(attr)) {
3977                 unit = unit || 'px';
3978                 superclass.setAttribute.call(this, 'left', val[0], unit);
3979                 superclass.setAttribute.call(this, 'top', val[1], unit);
3980             } else {
3981                 superclass.setAttribute.call(this, attr, val, unit);
3982             }
3983         };
3984
3985         proto.getAttribute = function(attr) {
3986             if (this.patterns.points.test(attr)) {
3987                 var val = [
3988                         superclass.getAttribute.call(this, 'left'),
3989                         superclass.getAttribute.call(this, 'top')
3990                         ];
3991             } else {
3992                 val = superclass.getAttribute.call(this, attr);
3993             }
3994
3995             return val;
3996         };
3997
3998         proto.doMethod = function(attr, start, end) {
3999             var val = null;
4000
4001             if (this.patterns.points.test(attr)) {
4002                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4003                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4004             } else {
4005                 val = superclass.doMethod.call(this, attr, start, end);
4006             }
4007             return val;
4008         };
4009
4010         proto.setRuntimeAttribute = function(attr) {
4011             if (this.patterns.points.test(attr)) {
4012                 var el = this.getEl();
4013                 var attributes = this.attributes;
4014                 var start;
4015                 var control = attributes['points']['control'] || [];
4016                 var end;
4017                 var i, len;
4018
4019                 if (control.length > 0 && !(control[0] instanceof Array)) {
4020                     control = [control];
4021                 } else {
4022                     var tmp = [];
4023                     for (i = 0,len = control.length; i < len; ++i) {
4024                         tmp[i] = control[i];
4025                     }
4026                     control = tmp;
4027                 }
4028
4029                 Roo.fly(el).position();
4030
4031                 if (isset(attributes['points']['from'])) {
4032                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4033                 }
4034                 else {
4035                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4036                 }
4037
4038                 start = this.getAttribute('points');
4039
4040
4041                 if (isset(attributes['points']['to'])) {
4042                     end = translateValues.call(this, attributes['points']['to'], start);
4043
4044                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4045                     for (i = 0,len = control.length; i < len; ++i) {
4046                         control[i] = translateValues.call(this, control[i], start);
4047                     }
4048
4049
4050                 } else if (isset(attributes['points']['by'])) {
4051                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4052
4053                     for (i = 0,len = control.length; i < len; ++i) {
4054                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4055                     }
4056                 }
4057
4058                 this.runtimeAttributes[attr] = [start];
4059
4060                 if (control.length > 0) {
4061                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4062                 }
4063
4064                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4065             }
4066             else {
4067                 superclass.setRuntimeAttribute.call(this, attr);
4068             }
4069         };
4070
4071         var translateValues = function(val, start) {
4072             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4073             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4074
4075             return val;
4076         };
4077
4078         var isset = function(prop) {
4079             return (typeof prop !== 'undefined');
4080         };
4081     })();
4082 /*
4083  * Portions of this file are based on pieces of Yahoo User Interface Library
4084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4085  * YUI licensed under the BSD License:
4086  * http://developer.yahoo.net/yui/license.txt
4087  * <script type="text/javascript">
4088  *
4089  */
4090     (function() {
4091         Roo.lib.Scroll = function(el, attributes, duration, method) {
4092             if (el) {
4093                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4094             }
4095         };
4096
4097         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4098
4099
4100         var Y = Roo.lib;
4101         var superclass = Y.Scroll.superclass;
4102         var proto = Y.Scroll.prototype;
4103
4104         proto.toString = function() {
4105             var el = this.getEl();
4106             var id = el.id || el.tagName;
4107             return ("Scroll " + id);
4108         };
4109
4110         proto.doMethod = function(attr, start, end) {
4111             var val = null;
4112
4113             if (attr == 'scroll') {
4114                 val = [
4115                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4116                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4117                         ];
4118
4119             } else {
4120                 val = superclass.doMethod.call(this, attr, start, end);
4121             }
4122             return val;
4123         };
4124
4125         proto.getAttribute = function(attr) {
4126             var val = null;
4127             var el = this.getEl();
4128
4129             if (attr == 'scroll') {
4130                 val = [ el.scrollLeft, el.scrollTop ];
4131             } else {
4132                 val = superclass.getAttribute.call(this, attr);
4133             }
4134
4135             return val;
4136         };
4137
4138         proto.setAttribute = function(attr, val, unit) {
4139             var el = this.getEl();
4140
4141             if (attr == 'scroll') {
4142                 el.scrollLeft = val[0];
4143                 el.scrollTop = val[1];
4144             } else {
4145                 superclass.setAttribute.call(this, attr, val, unit);
4146             }
4147         };
4148     })();
4149 /*
4150  * Based on:
4151  * Ext JS Library 1.1.1
4152  * Copyright(c) 2006-2007, Ext JS, LLC.
4153  *
4154  * Originally Released Under LGPL - original licence link has changed is not relivant.
4155  *
4156  * Fork - LGPL
4157  * <script type="text/javascript">
4158  */
4159
4160
4161 // nasty IE9 hack - what a pile of crap that is..
4162
4163  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4164     Range.prototype.createContextualFragment = function (html) {
4165         var doc = window.document;
4166         var container = doc.createElement("div");
4167         container.innerHTML = html;
4168         var frag = doc.createDocumentFragment(), n;
4169         while ((n = container.firstChild)) {
4170             frag.appendChild(n);
4171         }
4172         return frag;
4173     };
4174 }
4175
4176 /**
4177  * @class Roo.DomHelper
4178  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4179  * 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>.
4180  * @singleton
4181  */
4182 Roo.DomHelper = function(){
4183     var tempTableEl = null;
4184     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4185     var tableRe = /^table|tbody|tr|td$/i;
4186     var xmlns = {};
4187     // build as innerHTML where available
4188     /** @ignore */
4189     var createHtml = function(o){
4190         if(typeof o == 'string'){
4191             return o;
4192         }
4193         var b = "";
4194         if(!o.tag){
4195             o.tag = "div";
4196         }
4197         b += "<" + o.tag;
4198         for(var attr in o){
4199             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4200             if(attr == "style"){
4201                 var s = o["style"];
4202                 if(typeof s == "function"){
4203                     s = s.call();
4204                 }
4205                 if(typeof s == "string"){
4206                     b += ' style="' + s + '"';
4207                 }else if(typeof s == "object"){
4208                     b += ' style="';
4209                     for(var key in s){
4210                         if(typeof s[key] != "function"){
4211                             b += key + ":" + s[key] + ";";
4212                         }
4213                     }
4214                     b += '"';
4215                 }
4216             }else{
4217                 if(attr == "cls"){
4218                     b += ' class="' + o["cls"] + '"';
4219                 }else if(attr == "htmlFor"){
4220                     b += ' for="' + o["htmlFor"] + '"';
4221                 }else{
4222                     b += " " + attr + '="' + o[attr] + '"';
4223                 }
4224             }
4225         }
4226         if(emptyTags.test(o.tag)){
4227             b += "/>";
4228         }else{
4229             b += ">";
4230             var cn = o.children || o.cn;
4231             if(cn){
4232                 //http://bugs.kde.org/show_bug.cgi?id=71506
4233                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4234                     for(var i = 0, len = cn.length; i < len; i++) {
4235                         b += createHtml(cn[i], b);
4236                     }
4237                 }else{
4238                     b += createHtml(cn, b);
4239                 }
4240             }
4241             if(o.html){
4242                 b += o.html;
4243             }
4244             b += "</" + o.tag + ">";
4245         }
4246         return b;
4247     };
4248
4249     // build as dom
4250     /** @ignore */
4251     var createDom = function(o, parentNode){
4252          
4253         // defininition craeted..
4254         var ns = false;
4255         if (o.ns && o.ns != 'html') {
4256                
4257             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4258                 xmlns[o.ns] = o.xmlns;
4259                 ns = o.xmlns;
4260             }
4261             if (typeof(xmlns[o.ns]) == 'undefined') {
4262                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4263             }
4264             ns = xmlns[o.ns];
4265         }
4266         
4267         
4268         if (typeof(o) == 'string') {
4269             return parentNode.appendChild(document.createTextNode(o));
4270         }
4271         o.tag = o.tag || div;
4272         if (o.ns && Roo.isIE) {
4273             ns = false;
4274             o.tag = o.ns + ':' + o.tag;
4275             
4276         }
4277         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4278         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4279         for(var attr in o){
4280             
4281             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4282                     attr == "style" || typeof o[attr] == "function") { continue; }
4283                     
4284             if(attr=="cls" && Roo.isIE){
4285                 el.className = o["cls"];
4286             }else{
4287                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4288                 else { 
4289                     el[attr] = o[attr];
4290                 }
4291             }
4292         }
4293         Roo.DomHelper.applyStyles(el, o.style);
4294         var cn = o.children || o.cn;
4295         if(cn){
4296             //http://bugs.kde.org/show_bug.cgi?id=71506
4297              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4298                 for(var i = 0, len = cn.length; i < len; i++) {
4299                     createDom(cn[i], el);
4300                 }
4301             }else{
4302                 createDom(cn, el);
4303             }
4304         }
4305         if(o.html){
4306             el.innerHTML = o.html;
4307         }
4308         if(parentNode){
4309            parentNode.appendChild(el);
4310         }
4311         return el;
4312     };
4313
4314     var ieTable = function(depth, s, h, e){
4315         tempTableEl.innerHTML = [s, h, e].join('');
4316         var i = -1, el = tempTableEl;
4317         while(++i < depth){
4318             el = el.firstChild;
4319         }
4320         return el;
4321     };
4322
4323     // kill repeat to save bytes
4324     var ts = '<table>',
4325         te = '</table>',
4326         tbs = ts+'<tbody>',
4327         tbe = '</tbody>'+te,
4328         trs = tbs + '<tr>',
4329         tre = '</tr>'+tbe;
4330
4331     /**
4332      * @ignore
4333      * Nasty code for IE's broken table implementation
4334      */
4335     var insertIntoTable = function(tag, where, el, html){
4336         if(!tempTableEl){
4337             tempTableEl = document.createElement('div');
4338         }
4339         var node;
4340         var before = null;
4341         if(tag == 'td'){
4342             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4343                 return;
4344             }
4345             if(where == 'beforebegin'){
4346                 before = el;
4347                 el = el.parentNode;
4348             } else{
4349                 before = el.nextSibling;
4350                 el = el.parentNode;
4351             }
4352             node = ieTable(4, trs, html, tre);
4353         }
4354         else if(tag == 'tr'){
4355             if(where == 'beforebegin'){
4356                 before = el;
4357                 el = el.parentNode;
4358                 node = ieTable(3, tbs, html, tbe);
4359             } else if(where == 'afterend'){
4360                 before = el.nextSibling;
4361                 el = el.parentNode;
4362                 node = ieTable(3, tbs, html, tbe);
4363             } else{ // INTO a TR
4364                 if(where == 'afterbegin'){
4365                     before = el.firstChild;
4366                 }
4367                 node = ieTable(4, trs, html, tre);
4368             }
4369         } else if(tag == 'tbody'){
4370             if(where == 'beforebegin'){
4371                 before = el;
4372                 el = el.parentNode;
4373                 node = ieTable(2, ts, html, te);
4374             } else if(where == 'afterend'){
4375                 before = el.nextSibling;
4376                 el = el.parentNode;
4377                 node = ieTable(2, ts, html, te);
4378             } else{
4379                 if(where == 'afterbegin'){
4380                     before = el.firstChild;
4381                 }
4382                 node = ieTable(3, tbs, html, tbe);
4383             }
4384         } else{ // TABLE
4385             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4386                 return;
4387             }
4388             if(where == 'afterbegin'){
4389                 before = el.firstChild;
4390             }
4391             node = ieTable(2, ts, html, te);
4392         }
4393         el.insertBefore(node, before);
4394         return node;
4395     };
4396
4397     return {
4398     /** True to force the use of DOM instead of html fragments @type Boolean */
4399     useDom : false,
4400
4401     /**
4402      * Returns the markup for the passed Element(s) config
4403      * @param {Object} o The Dom object spec (and children)
4404      * @return {String}
4405      */
4406     markup : function(o){
4407         return createHtml(o);
4408     },
4409
4410     /**
4411      * Applies a style specification to an element
4412      * @param {String/HTMLElement} el The element to apply styles to
4413      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4414      * a function which returns such a specification.
4415      */
4416     applyStyles : function(el, styles){
4417         if(styles){
4418            el = Roo.fly(el);
4419            if(typeof styles == "string"){
4420                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4421                var matches;
4422                while ((matches = re.exec(styles)) != null){
4423                    el.setStyle(matches[1], matches[2]);
4424                }
4425            }else if (typeof styles == "object"){
4426                for (var style in styles){
4427                   el.setStyle(style, styles[style]);
4428                }
4429            }else if (typeof styles == "function"){
4430                 Roo.DomHelper.applyStyles(el, styles.call());
4431            }
4432         }
4433     },
4434
4435     /**
4436      * Inserts an HTML fragment into the Dom
4437      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4438      * @param {HTMLElement} el The context element
4439      * @param {String} html The HTML fragmenet
4440      * @return {HTMLElement} The new node
4441      */
4442     insertHtml : function(where, el, html){
4443         where = where.toLowerCase();
4444         if(el.insertAdjacentHTML){
4445             if(tableRe.test(el.tagName)){
4446                 var rs;
4447                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4448                     return rs;
4449                 }
4450             }
4451             switch(where){
4452                 case "beforebegin":
4453                     el.insertAdjacentHTML('BeforeBegin', html);
4454                     return el.previousSibling;
4455                 case "afterbegin":
4456                     el.insertAdjacentHTML('AfterBegin', html);
4457                     return el.firstChild;
4458                 case "beforeend":
4459                     el.insertAdjacentHTML('BeforeEnd', html);
4460                     return el.lastChild;
4461                 case "afterend":
4462                     el.insertAdjacentHTML('AfterEnd', html);
4463                     return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466         }
4467         var range = el.ownerDocument.createRange();
4468         var frag;
4469         switch(where){
4470              case "beforebegin":
4471                 range.setStartBefore(el);
4472                 frag = range.createContextualFragment(html);
4473                 el.parentNode.insertBefore(frag, el);
4474                 return el.previousSibling;
4475              case "afterbegin":
4476                 if(el.firstChild){
4477                     range.setStartBefore(el.firstChild);
4478                     frag = range.createContextualFragment(html);
4479                     el.insertBefore(frag, el.firstChild);
4480                     return el.firstChild;
4481                 }else{
4482                     el.innerHTML = html;
4483                     return el.firstChild;
4484                 }
4485             case "beforeend":
4486                 if(el.lastChild){
4487                     range.setStartAfter(el.lastChild);
4488                     frag = range.createContextualFragment(html);
4489                     el.appendChild(frag);
4490                     return el.lastChild;
4491                 }else{
4492                     el.innerHTML = html;
4493                     return el.lastChild;
4494                 }
4495             case "afterend":
4496                 range.setStartAfter(el);
4497                 frag = range.createContextualFragment(html);
4498                 el.parentNode.insertBefore(frag, el.nextSibling);
4499                 return el.nextSibling;
4500             }
4501             throw 'Illegal insertion point -> "' + where + '"';
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and inserts them before el
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     insertBefore : function(el, o, returnElement){
4512         return this.doInsert(el, o, returnElement, "beforeBegin");
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and inserts them after el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object} o The Dom object spec (and children)
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     insertAfter : function(el, o, returnElement){
4523         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4524     },
4525
4526     /**
4527      * Creates new Dom element(s) and inserts them as the first child of 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     insertFirst : function(el, o, returnElement){
4534         return this.doInsert(el, o, returnElement, "afterBegin");
4535     },
4536
4537     // private
4538     doInsert : function(el, o, returnElement, pos, sibling){
4539         el = Roo.getDom(el);
4540         var newNode;
4541         if(this.useDom || o.ns){
4542             newNode = createDom(o, null);
4543             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4544         }else{
4545             var html = createHtml(o);
4546             newNode = this.insertHtml(pos, el, html);
4547         }
4548         return returnElement ? Roo.get(newNode, true) : newNode;
4549     },
4550
4551     /**
4552      * Creates new Dom element(s) and appends them to el
4553      * @param {String/HTMLElement/Element} el The context element
4554      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4555      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4556      * @return {HTMLElement/Roo.Element} The new node
4557      */
4558     append : function(el, o, returnElement){
4559         el = Roo.getDom(el);
4560         var newNode;
4561         if(this.useDom || o.ns){
4562             newNode = createDom(o, null);
4563             el.appendChild(newNode);
4564         }else{
4565             var html = createHtml(o);
4566             newNode = this.insertHtml("beforeEnd", el, html);
4567         }
4568         return returnElement ? Roo.get(newNode, true) : newNode;
4569     },
4570
4571     /**
4572      * Creates new Dom element(s) and overwrites the contents of el with them
4573      * @param {String/HTMLElement/Element} el The context element
4574      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4575      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4576      * @return {HTMLElement/Roo.Element} The new node
4577      */
4578     overwrite : function(el, o, returnElement){
4579         el = Roo.getDom(el);
4580         if (o.ns) {
4581           
4582             while (el.childNodes.length) {
4583                 el.removeChild(el.firstChild);
4584             }
4585             createDom(o, el);
4586         } else {
4587             el.innerHTML = createHtml(o);   
4588         }
4589         
4590         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4591     },
4592
4593     /**
4594      * Creates a new Roo.DomHelper.Template from the Dom object spec
4595      * @param {Object} o The Dom object spec (and children)
4596      * @return {Roo.DomHelper.Template} The new template
4597      */
4598     createTemplate : function(o){
4599         var html = createHtml(o);
4600         return new Roo.Template(html);
4601     }
4602     };
4603 }();
4604 /*
4605  * Based on:
4606  * Ext JS Library 1.1.1
4607  * Copyright(c) 2006-2007, Ext JS, LLC.
4608  *
4609  * Originally Released Under LGPL - original licence link has changed is not relivant.
4610  *
4611  * Fork - LGPL
4612  * <script type="text/javascript">
4613  */
4614  
4615 /**
4616 * @class Roo.Template
4617 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4618 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4619 * Usage:
4620 <pre><code>
4621 var t = new Roo.Template({
4622     html :  '&lt;div name="{id}"&gt;' + 
4623         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4624         '&lt;/div&gt;',
4625     myformat: function (value, allValues) {
4626         return 'XX' + value;
4627     }
4628 });
4629 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4630 </code></pre>
4631 * For more information see this blog post with examples:
4632 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4633      - Create Elements using DOM, HTML fragments and Templates</a>. 
4634 * @constructor
4635 * @param {Object} cfg - Configuration object.
4636 */
4637 Roo.Template = function(cfg){
4638     // BC!
4639     if(cfg instanceof Array){
4640         cfg = cfg.join("");
4641     }else if(arguments.length > 1){
4642         cfg = Array.prototype.join.call(arguments, "");
4643     }
4644     
4645     
4646     if (typeof(cfg) == 'object') {
4647         Roo.apply(this,cfg)
4648     } else {
4649         // bc
4650         this.html = cfg;
4651     }
4652     if (this.url) {
4653         this.load();
4654     }
4655     
4656 };
4657 Roo.Template.prototype = {
4658     
4659     /**
4660      * @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..
4661      *                    it should be fixed so that template is observable...
4662      */
4663     url : false,
4664     /**
4665      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4666      */
4667     html : '',
4668     /**
4669      * Returns an HTML fragment of this template with the specified values applied.
4670      * @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'})
4671      * @return {String} The HTML fragment
4672      */
4673     applyTemplate : function(values){
4674         try {
4675            
4676             if(this.compiled){
4677                 return this.compiled(values);
4678             }
4679             var useF = this.disableFormats !== true;
4680             var fm = Roo.util.Format, tpl = this;
4681             var fn = function(m, name, format, args){
4682                 if(format && useF){
4683                     if(format.substr(0, 5) == "this."){
4684                         return tpl.call(format.substr(5), values[name], values);
4685                     }else{
4686                         if(args){
4687                             // quoted values are required for strings in compiled templates, 
4688                             // but for non compiled we need to strip them
4689                             // quoted reversed for jsmin
4690                             var re = /^\s*['"](.*)["']\s*$/;
4691                             args = args.split(',');
4692                             for(var i = 0, len = args.length; i < len; i++){
4693                                 args[i] = args[i].replace(re, "$1");
4694                             }
4695                             args = [values[name]].concat(args);
4696                         }else{
4697                             args = [values[name]];
4698                         }
4699                         return fm[format].apply(fm, args);
4700                     }
4701                 }else{
4702                     return values[name] !== undefined ? values[name] : "";
4703                 }
4704             };
4705             return this.html.replace(this.re, fn);
4706         } catch (e) {
4707             Roo.log(e);
4708             throw e;
4709         }
4710          
4711     },
4712     
4713     loading : false,
4714       
4715     load : function ()
4716     {
4717          
4718         if (this.loading) {
4719             return;
4720         }
4721         var _t = this;
4722         
4723         this.loading = true;
4724         this.compiled = false;
4725         
4726         var cx = new Roo.data.Connection();
4727         cx.request({
4728             url : this.url,
4729             method : 'GET',
4730             success : function (response) {
4731                 _t.loading = false;
4732                 _t.html = response.responseText;
4733                 _t.url = false;
4734                 _t.compile();
4735              },
4736             failure : function(response) {
4737                 Roo.log("Template failed to load from " + _t.url);
4738                 _t.loading = false;
4739             }
4740         });
4741     },
4742
4743     /**
4744      * Sets the HTML used as the template and optionally compiles it.
4745      * @param {String} html
4746      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4747      * @return {Roo.Template} this
4748      */
4749     set : function(html, compile){
4750         this.html = html;
4751         this.compiled = null;
4752         if(compile){
4753             this.compile();
4754         }
4755         return this;
4756     },
4757     
4758     /**
4759      * True to disable format functions (defaults to false)
4760      * @type Boolean
4761      */
4762     disableFormats : false,
4763     
4764     /**
4765     * The regular expression used to match template variables 
4766     * @type RegExp
4767     * @property 
4768     */
4769     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4770     
4771     /**
4772      * Compiles the template into an internal function, eliminating the RegEx overhead.
4773      * @return {Roo.Template} this
4774      */
4775     compile : function(){
4776         var fm = Roo.util.Format;
4777         var useF = this.disableFormats !== true;
4778         var sep = Roo.isGecko ? "+" : ",";
4779         var fn = function(m, name, format, args){
4780             if(format && useF){
4781                 args = args ? ',' + args : "";
4782                 if(format.substr(0, 5) != "this."){
4783                     format = "fm." + format + '(';
4784                 }else{
4785                     format = 'this.call("'+ format.substr(5) + '", ';
4786                     args = ", values";
4787                 }
4788             }else{
4789                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4790             }
4791             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4792         };
4793         var body;
4794         // branched to use + in gecko and [].join() in others
4795         if(Roo.isGecko){
4796             body = "this.compiled = function(values){ return '" +
4797                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4798                     "';};";
4799         }else{
4800             body = ["this.compiled = function(values){ return ['"];
4801             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4802             body.push("'].join('');};");
4803             body = body.join('');
4804         }
4805         /**
4806          * eval:var:values
4807          * eval:var:fm
4808          */
4809         eval(body);
4810         return this;
4811     },
4812     
4813     // private function used to call members
4814     call : function(fnName, value, allValues){
4815         return this[fnName](value, allValues);
4816     },
4817     
4818     /**
4819      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     insertFirst: function(el, values, returnElement){
4826         return this.doInsert('afterBegin', el, values, returnElement);
4827     },
4828
4829     /**
4830      * Applies the supplied values to the template and inserts the new node(s) before el.
4831      * @param {String/HTMLElement/Roo.Element} el The context element
4832      * @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'})
4833      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4834      * @return {HTMLElement/Roo.Element} The new node or Element
4835      */
4836     insertBefore: function(el, values, returnElement){
4837         return this.doInsert('beforeBegin', el, values, returnElement);
4838     },
4839
4840     /**
4841      * Applies the supplied values to the template and inserts the new node(s) after el.
4842      * @param {String/HTMLElement/Roo.Element} el The context element
4843      * @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'})
4844      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4845      * @return {HTMLElement/Roo.Element} The new node or Element
4846      */
4847     insertAfter : function(el, values, returnElement){
4848         return this.doInsert('afterEnd', el, values, returnElement);
4849     },
4850     
4851     /**
4852      * Applies the supplied values to the template and appends the new node(s) to el.
4853      * @param {String/HTMLElement/Roo.Element} el The context element
4854      * @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'})
4855      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4856      * @return {HTMLElement/Roo.Element} The new node or Element
4857      */
4858     append : function(el, values, returnElement){
4859         return this.doInsert('beforeEnd', el, values, returnElement);
4860     },
4861
4862     doInsert : function(where, el, values, returnEl){
4863         el = Roo.getDom(el);
4864         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4865         return returnEl ? Roo.get(newNode, true) : newNode;
4866     },
4867
4868     /**
4869      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4870      * @param {String/HTMLElement/Roo.Element} el The context element
4871      * @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'})
4872      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4873      * @return {HTMLElement/Roo.Element} The new node or Element
4874      */
4875     overwrite : function(el, values, returnElement){
4876         el = Roo.getDom(el);
4877         el.innerHTML = this.applyTemplate(values);
4878         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4879     }
4880 };
4881 /**
4882  * Alias for {@link #applyTemplate}
4883  * @method
4884  */
4885 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4886
4887 // backwards compat
4888 Roo.DomHelper.Template = Roo.Template;
4889
4890 /**
4891  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4892  * @param {String/HTMLElement} el A DOM element or its id
4893  * @returns {Roo.Template} The created template
4894  * @static
4895  */
4896 Roo.Template.from = function(el){
4897     el = Roo.getDom(el);
4898     return new Roo.Template(el.value || el.innerHTML);
4899 };/*
4900  * Based on:
4901  * Ext JS Library 1.1.1
4902  * Copyright(c) 2006-2007, Ext JS, LLC.
4903  *
4904  * Originally Released Under LGPL - original licence link has changed is not relivant.
4905  *
4906  * Fork - LGPL
4907  * <script type="text/javascript">
4908  */
4909  
4910
4911 /*
4912  * This is code is also distributed under MIT license for use
4913  * with jQuery and prototype JavaScript libraries.
4914  */
4915 /**
4916  * @class Roo.DomQuery
4917 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).
4918 <p>
4919 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>
4920
4921 <p>
4922 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.
4923 </p>
4924 <h4>Element Selectors:</h4>
4925 <ul class="list">
4926     <li> <b>*</b> any element</li>
4927     <li> <b>E</b> an element with the tag E</li>
4928     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4929     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4930     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4931     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4932 </ul>
4933 <h4>Attribute Selectors:</h4>
4934 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4935 <ul class="list">
4936     <li> <b>E[foo]</b> has an attribute "foo"</li>
4937     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4938     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4939     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4940     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4941     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4942     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4943 </ul>
4944 <h4>Pseudo Classes:</h4>
4945 <ul class="list">
4946     <li> <b>E:first-child</b> E is the first child of its parent</li>
4947     <li> <b>E:last-child</b> E is the last child of its parent</li>
4948     <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>
4949     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4950     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4951     <li> <b>E:only-child</b> E is the only child of its parent</li>
4952     <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>
4953     <li> <b>E:first</b> the first E in the resultset</li>
4954     <li> <b>E:last</b> the last E in the resultset</li>
4955     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4956     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4957     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4958     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4959     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4960     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4961     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4962     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4963     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4964 </ul>
4965 <h4>CSS Value Selectors:</h4>
4966 <ul class="list">
4967     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4968     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4969     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4970     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4971     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4972     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4973 </ul>
4974  * @singleton
4975  */
4976 Roo.DomQuery = function(){
4977     var cache = {}, simpleCache = {}, valueCache = {};
4978     var nonSpace = /\S/;
4979     var trimRe = /^\s+|\s+$/g;
4980     var tplRe = /\{(\d+)\}/g;
4981     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4982     var tagTokenRe = /^(#)?([\w-\*]+)/;
4983     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4984
4985     function child(p, index){
4986         var i = 0;
4987         var n = p.firstChild;
4988         while(n){
4989             if(n.nodeType == 1){
4990                if(++i == index){
4991                    return n;
4992                }
4993             }
4994             n = n.nextSibling;
4995         }
4996         return null;
4997     };
4998
4999     function next(n){
5000         while((n = n.nextSibling) && n.nodeType != 1);
5001         return n;
5002     };
5003
5004     function prev(n){
5005         while((n = n.previousSibling) && n.nodeType != 1);
5006         return n;
5007     };
5008
5009     function children(d){
5010         var n = d.firstChild, ni = -1;
5011             while(n){
5012                 var nx = n.nextSibling;
5013                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5014                     d.removeChild(n);
5015                 }else{
5016                     n.nodeIndex = ++ni;
5017                 }
5018                 n = nx;
5019             }
5020             return this;
5021         };
5022
5023     function byClassName(c, a, v){
5024         if(!v){
5025             return c;
5026         }
5027         var r = [], ri = -1, cn;
5028         for(var i = 0, ci; ci = c[i]; i++){
5029             if((' '+ci.className+' ').indexOf(v) != -1){
5030                 r[++ri] = ci;
5031             }
5032         }
5033         return r;
5034     };
5035
5036     function attrValue(n, attr){
5037         if(!n.tagName && typeof n.length != "undefined"){
5038             n = n[0];
5039         }
5040         if(!n){
5041             return null;
5042         }
5043         if(attr == "for"){
5044             return n.htmlFor;
5045         }
5046         if(attr == "class" || attr == "className"){
5047             return n.className;
5048         }
5049         return n.getAttribute(attr) || n[attr];
5050
5051     };
5052
5053     function getNodes(ns, mode, tagName){
5054         var result = [], ri = -1, cs;
5055         if(!ns){
5056             return result;
5057         }
5058         tagName = tagName || "*";
5059         if(typeof ns.getElementsByTagName != "undefined"){
5060             ns = [ns];
5061         }
5062         if(!mode){
5063             for(var i = 0, ni; ni = ns[i]; i++){
5064                 cs = ni.getElementsByTagName(tagName);
5065                 for(var j = 0, ci; ci = cs[j]; j++){
5066                     result[++ri] = ci;
5067                 }
5068             }
5069         }else if(mode == "/" || mode == ">"){
5070             var utag = tagName.toUpperCase();
5071             for(var i = 0, ni, cn; ni = ns[i]; i++){
5072                 cn = ni.children || ni.childNodes;
5073                 for(var j = 0, cj; cj = cn[j]; j++){
5074                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5075                         result[++ri] = cj;
5076                     }
5077                 }
5078             }
5079         }else if(mode == "+"){
5080             var utag = tagName.toUpperCase();
5081             for(var i = 0, n; n = ns[i]; i++){
5082                 while((n = n.nextSibling) && n.nodeType != 1);
5083                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5084                     result[++ri] = n;
5085                 }
5086             }
5087         }else if(mode == "~"){
5088             for(var i = 0, n; n = ns[i]; i++){
5089                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5090                 if(n){
5091                     result[++ri] = n;
5092                 }
5093             }
5094         }
5095         return result;
5096     };
5097
5098     function concat(a, b){
5099         if(b.slice){
5100             return a.concat(b);
5101         }
5102         for(var i = 0, l = b.length; i < l; i++){
5103             a[a.length] = b[i];
5104         }
5105         return a;
5106     }
5107
5108     function byTag(cs, tagName){
5109         if(cs.tagName || cs == document){
5110             cs = [cs];
5111         }
5112         if(!tagName){
5113             return cs;
5114         }
5115         var r = [], ri = -1;
5116         tagName = tagName.toLowerCase();
5117         for(var i = 0, ci; ci = cs[i]; i++){
5118             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5119                 r[++ri] = ci;
5120             }
5121         }
5122         return r;
5123     };
5124
5125     function byId(cs, attr, id){
5126         if(cs.tagName || cs == document){
5127             cs = [cs];
5128         }
5129         if(!id){
5130             return cs;
5131         }
5132         var r = [], ri = -1;
5133         for(var i = 0,ci; ci = cs[i]; i++){
5134             if(ci && ci.id == id){
5135                 r[++ri] = ci;
5136                 return r;
5137             }
5138         }
5139         return r;
5140     };
5141
5142     function byAttribute(cs, attr, value, op, custom){
5143         var r = [], ri = -1, st = custom=="{";
5144         var f = Roo.DomQuery.operators[op];
5145         for(var i = 0, ci; ci = cs[i]; i++){
5146             var a;
5147             if(st){
5148                 a = Roo.DomQuery.getStyle(ci, attr);
5149             }
5150             else if(attr == "class" || attr == "className"){
5151                 a = ci.className;
5152             }else if(attr == "for"){
5153                 a = ci.htmlFor;
5154             }else if(attr == "href"){
5155                 a = ci.getAttribute("href", 2);
5156             }else{
5157                 a = ci.getAttribute(attr);
5158             }
5159             if((f && f(a, value)) || (!f && a)){
5160                 r[++ri] = ci;
5161             }
5162         }
5163         return r;
5164     };
5165
5166     function byPseudo(cs, name, value){
5167         return Roo.DomQuery.pseudos[name](cs, value);
5168     };
5169
5170     // This is for IE MSXML which does not support expandos.
5171     // IE runs the same speed using setAttribute, however FF slows way down
5172     // and Safari completely fails so they need to continue to use expandos.
5173     var isIE = window.ActiveXObject ? true : false;
5174
5175     // this eval is stop the compressor from
5176     // renaming the variable to something shorter
5177     
5178     /** eval:var:batch */
5179     var batch = 30803; 
5180
5181     var key = 30803;
5182
5183     function nodupIEXml(cs){
5184         var d = ++key;
5185         cs[0].setAttribute("_nodup", d);
5186         var r = [cs[0]];
5187         for(var i = 1, len = cs.length; i < len; i++){
5188             var c = cs[i];
5189             if(!c.getAttribute("_nodup") != d){
5190                 c.setAttribute("_nodup", d);
5191                 r[r.length] = c;
5192             }
5193         }
5194         for(var i = 0, len = cs.length; i < len; i++){
5195             cs[i].removeAttribute("_nodup");
5196         }
5197         return r;
5198     }
5199
5200     function nodup(cs){
5201         if(!cs){
5202             return [];
5203         }
5204         var len = cs.length, c, i, r = cs, cj, ri = -1;
5205         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5206             return cs;
5207         }
5208         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5209             return nodupIEXml(cs);
5210         }
5211         var d = ++key;
5212         cs[0]._nodup = d;
5213         for(i = 1; c = cs[i]; i++){
5214             if(c._nodup != d){
5215                 c._nodup = d;
5216             }else{
5217                 r = [];
5218                 for(var j = 0; j < i; j++){
5219                     r[++ri] = cs[j];
5220                 }
5221                 for(j = i+1; cj = cs[j]; j++){
5222                     if(cj._nodup != d){
5223                         cj._nodup = d;
5224                         r[++ri] = cj;
5225                     }
5226                 }
5227                 return r;
5228             }
5229         }
5230         return r;
5231     }
5232
5233     function quickDiffIEXml(c1, c2){
5234         var d = ++key;
5235         for(var i = 0, len = c1.length; i < len; i++){
5236             c1[i].setAttribute("_qdiff", d);
5237         }
5238         var r = [];
5239         for(var i = 0, len = c2.length; i < len; i++){
5240             if(c2[i].getAttribute("_qdiff") != d){
5241                 r[r.length] = c2[i];
5242             }
5243         }
5244         for(var i = 0, len = c1.length; i < len; i++){
5245            c1[i].removeAttribute("_qdiff");
5246         }
5247         return r;
5248     }
5249
5250     function quickDiff(c1, c2){
5251         var len1 = c1.length;
5252         if(!len1){
5253             return c2;
5254         }
5255         if(isIE && c1[0].selectSingleNode){
5256             return quickDiffIEXml(c1, c2);
5257         }
5258         var d = ++key;
5259         for(var i = 0; i < len1; i++){
5260             c1[i]._qdiff = d;
5261         }
5262         var r = [];
5263         for(var i = 0, len = c2.length; i < len; i++){
5264             if(c2[i]._qdiff != d){
5265                 r[r.length] = c2[i];
5266             }
5267         }
5268         return r;
5269     }
5270
5271     function quickId(ns, mode, root, id){
5272         if(ns == root){
5273            var d = root.ownerDocument || root;
5274            return d.getElementById(id);
5275         }
5276         ns = getNodes(ns, mode, "*");
5277         return byId(ns, null, id);
5278     }
5279
5280     return {
5281         getStyle : function(el, name){
5282             return Roo.fly(el).getStyle(name);
5283         },
5284         /**
5285          * Compiles a selector/xpath query into a reusable function. The returned function
5286          * takes one parameter "root" (optional), which is the context node from where the query should start.
5287          * @param {String} selector The selector/xpath query
5288          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5289          * @return {Function}
5290          */
5291         compile : function(path, type){
5292             type = type || "select";
5293             
5294             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5295             var q = path, mode, lq;
5296             var tk = Roo.DomQuery.matchers;
5297             var tklen = tk.length;
5298             var mm;
5299
5300             // accept leading mode switch
5301             var lmode = q.match(modeRe);
5302             if(lmode && lmode[1]){
5303                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5304                 q = q.replace(lmode[1], "");
5305             }
5306             // strip leading slashes
5307             while(path.substr(0, 1)=="/"){
5308                 path = path.substr(1);
5309             }
5310
5311             while(q && lq != q){
5312                 lq = q;
5313                 var tm = q.match(tagTokenRe);
5314                 if(type == "select"){
5315                     if(tm){
5316                         if(tm[1] == "#"){
5317                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5318                         }else{
5319                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5320                         }
5321                         q = q.replace(tm[0], "");
5322                     }else if(q.substr(0, 1) != '@'){
5323                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5324                     }
5325                 }else{
5326                     if(tm){
5327                         if(tm[1] == "#"){
5328                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5329                         }else{
5330                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5331                         }
5332                         q = q.replace(tm[0], "");
5333                     }
5334                 }
5335                 while(!(mm = q.match(modeRe))){
5336                     var matched = false;
5337                     for(var j = 0; j < tklen; j++){
5338                         var t = tk[j];
5339                         var m = q.match(t.re);
5340                         if(m){
5341                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5342                                                     return m[i];
5343                                                 });
5344                             q = q.replace(m[0], "");
5345                             matched = true;
5346                             break;
5347                         }
5348                     }
5349                     // prevent infinite loop on bad selector
5350                     if(!matched){
5351                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5352                     }
5353                 }
5354                 if(mm[1]){
5355                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5356                     q = q.replace(mm[1], "");
5357                 }
5358             }
5359             fn[fn.length] = "return nodup(n);\n}";
5360             
5361              /** 
5362               * list of variables that need from compression as they are used by eval.
5363              *  eval:var:batch 
5364              *  eval:var:nodup
5365              *  eval:var:byTag
5366              *  eval:var:ById
5367              *  eval:var:getNodes
5368              *  eval:var:quickId
5369              *  eval:var:mode
5370              *  eval:var:root
5371              *  eval:var:n
5372              *  eval:var:byClassName
5373              *  eval:var:byPseudo
5374              *  eval:var:byAttribute
5375              *  eval:var:attrValue
5376              * 
5377              **/ 
5378             eval(fn.join(""));
5379             return f;
5380         },
5381
5382         /**
5383          * Selects a group of elements.
5384          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5385          * @param {Node} root (optional) The start of the query (defaults to document).
5386          * @return {Array}
5387          */
5388         select : function(path, root, type){
5389             if(!root || root == document){
5390                 root = document;
5391             }
5392             if(typeof root == "string"){
5393                 root = document.getElementById(root);
5394             }
5395             var paths = path.split(",");
5396             var results = [];
5397             for(var i = 0, len = paths.length; i < len; i++){
5398                 var p = paths[i].replace(trimRe, "");
5399                 if(!cache[p]){
5400                     cache[p] = Roo.DomQuery.compile(p);
5401                     if(!cache[p]){
5402                         throw p + " is not a valid selector";
5403                     }
5404                 }
5405                 var result = cache[p](root);
5406                 if(result && result != document){
5407                     results = results.concat(result);
5408                 }
5409             }
5410             if(paths.length > 1){
5411                 return nodup(results);
5412             }
5413             return results;
5414         },
5415
5416         /**
5417          * Selects a single element.
5418          * @param {String} selector The selector/xpath query
5419          * @param {Node} root (optional) The start of the query (defaults to document).
5420          * @return {Element}
5421          */
5422         selectNode : function(path, root){
5423             return Roo.DomQuery.select(path, root)[0];
5424         },
5425
5426         /**
5427          * Selects the value of a node, optionally replacing null with the defaultValue.
5428          * @param {String} selector The selector/xpath query
5429          * @param {Node} root (optional) The start of the query (defaults to document).
5430          * @param {String} defaultValue
5431          */
5432         selectValue : function(path, root, defaultValue){
5433             path = path.replace(trimRe, "");
5434             if(!valueCache[path]){
5435                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5436             }
5437             var n = valueCache[path](root);
5438             n = n[0] ? n[0] : n;
5439             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5440             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5441         },
5442
5443         /**
5444          * Selects the value of a node, parsing integers and floats.
5445          * @param {String} selector The selector/xpath query
5446          * @param {Node} root (optional) The start of the query (defaults to document).
5447          * @param {Number} defaultValue
5448          * @return {Number}
5449          */
5450         selectNumber : function(path, root, defaultValue){
5451             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5452             return parseFloat(v);
5453         },
5454
5455         /**
5456          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5457          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5458          * @param {String} selector The simple selector to test
5459          * @return {Boolean}
5460          */
5461         is : function(el, ss){
5462             if(typeof el == "string"){
5463                 el = document.getElementById(el);
5464             }
5465             var isArray = (el instanceof Array);
5466             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5467             return isArray ? (result.length == el.length) : (result.length > 0);
5468         },
5469
5470         /**
5471          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5472          * @param {Array} el An array of elements to filter
5473          * @param {String} selector The simple selector to test
5474          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5475          * the selector instead of the ones that match
5476          * @return {Array}
5477          */
5478         filter : function(els, ss, nonMatches){
5479             ss = ss.replace(trimRe, "");
5480             if(!simpleCache[ss]){
5481                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5482             }
5483             var result = simpleCache[ss](els);
5484             return nonMatches ? quickDiff(result, els) : result;
5485         },
5486
5487         /**
5488          * Collection of matching regular expressions and code snippets.
5489          */
5490         matchers : [{
5491                 re: /^\.([\w-]+)/,
5492                 select: 'n = byClassName(n, null, " {1} ");'
5493             }, {
5494                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5495                 select: 'n = byPseudo(n, "{1}", "{2}");'
5496             },{
5497                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5498                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5499             }, {
5500                 re: /^#([\w-]+)/,
5501                 select: 'n = byId(n, null, "{1}");'
5502             },{
5503                 re: /^@([\w-]+)/,
5504                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5505             }
5506         ],
5507
5508         /**
5509          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5510          * 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;.
5511          */
5512         operators : {
5513             "=" : function(a, v){
5514                 return a == v;
5515             },
5516             "!=" : function(a, v){
5517                 return a != v;
5518             },
5519             "^=" : function(a, v){
5520                 return a && a.substr(0, v.length) == v;
5521             },
5522             "$=" : function(a, v){
5523                 return a && a.substr(a.length-v.length) == v;
5524             },
5525             "*=" : function(a, v){
5526                 return a && a.indexOf(v) !== -1;
5527             },
5528             "%=" : function(a, v){
5529                 return (a % v) == 0;
5530             },
5531             "|=" : function(a, v){
5532                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5533             },
5534             "~=" : function(a, v){
5535                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5536             }
5537         },
5538
5539         /**
5540          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5541          * and the argument (if any) supplied in the selector.
5542          */
5543         pseudos : {
5544             "first-child" : function(c){
5545                 var r = [], ri = -1, n;
5546                 for(var i = 0, ci; ci = n = c[i]; i++){
5547                     while((n = n.previousSibling) && n.nodeType != 1);
5548                     if(!n){
5549                         r[++ri] = ci;
5550                     }
5551                 }
5552                 return r;
5553             },
5554
5555             "last-child" : function(c){
5556                 var r = [], ri = -1, n;
5557                 for(var i = 0, ci; ci = n = c[i]; i++){
5558                     while((n = n.nextSibling) && n.nodeType != 1);
5559                     if(!n){
5560                         r[++ri] = ci;
5561                     }
5562                 }
5563                 return r;
5564             },
5565
5566             "nth-child" : function(c, a) {
5567                 var r = [], ri = -1;
5568                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5569                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5570                 for(var i = 0, n; n = c[i]; i++){
5571                     var pn = n.parentNode;
5572                     if (batch != pn._batch) {
5573                         var j = 0;
5574                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5575                             if(cn.nodeType == 1){
5576                                cn.nodeIndex = ++j;
5577                             }
5578                         }
5579                         pn._batch = batch;
5580                     }
5581                     if (f == 1) {
5582                         if (l == 0 || n.nodeIndex == l){
5583                             r[++ri] = n;
5584                         }
5585                     } else if ((n.nodeIndex + l) % f == 0){
5586                         r[++ri] = n;
5587                     }
5588                 }
5589
5590                 return r;
5591             },
5592
5593             "only-child" : function(c){
5594                 var r = [], ri = -1;;
5595                 for(var i = 0, ci; ci = c[i]; i++){
5596                     if(!prev(ci) && !next(ci)){
5597                         r[++ri] = ci;
5598                     }
5599                 }
5600                 return r;
5601             },
5602
5603             "empty" : function(c){
5604                 var r = [], ri = -1;
5605                 for(var i = 0, ci; ci = c[i]; i++){
5606                     var cns = ci.childNodes, j = 0, cn, empty = true;
5607                     while(cn = cns[j]){
5608                         ++j;
5609                         if(cn.nodeType == 1 || cn.nodeType == 3){
5610                             empty = false;
5611                             break;
5612                         }
5613                     }
5614                     if(empty){
5615                         r[++ri] = ci;
5616                     }
5617                 }
5618                 return r;
5619             },
5620
5621             "contains" : function(c, v){
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "nodeValue" : function(c, v){
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "checked" : function(c){
5642                 var r = [], ri = -1;
5643                 for(var i = 0, ci; ci = c[i]; i++){
5644                     if(ci.checked == true){
5645                         r[++ri] = ci;
5646                     }
5647                 }
5648                 return r;
5649             },
5650
5651             "not" : function(c, ss){
5652                 return Roo.DomQuery.filter(c, ss, true);
5653             },
5654
5655             "odd" : function(c){
5656                 return this["nth-child"](c, "odd");
5657             },
5658
5659             "even" : function(c){
5660                 return this["nth-child"](c, "even");
5661             },
5662
5663             "nth" : function(c, a){
5664                 return c[a-1] || [];
5665             },
5666
5667             "first" : function(c){
5668                 return c[0] || [];
5669             },
5670
5671             "last" : function(c){
5672                 return c[c.length-1] || [];
5673             },
5674
5675             "has" : function(c, ss){
5676                 var s = Roo.DomQuery.select;
5677                 var r = [], ri = -1;
5678                 for(var i = 0, ci; ci = c[i]; i++){
5679                     if(s(ss, ci).length > 0){
5680                         r[++ri] = ci;
5681                     }
5682                 }
5683                 return r;
5684             },
5685
5686             "next" : function(c, ss){
5687                 var is = Roo.DomQuery.is;
5688                 var r = [], ri = -1;
5689                 for(var i = 0, ci; ci = c[i]; i++){
5690                     var n = next(ci);
5691                     if(n && is(n, ss)){
5692                         r[++ri] = ci;
5693                     }
5694                 }
5695                 return r;
5696             },
5697
5698             "prev" : function(c, ss){
5699                 var is = Roo.DomQuery.is;
5700                 var r = [], ri = -1;
5701                 for(var i = 0, ci; ci = c[i]; i++){
5702                     var n = prev(ci);
5703                     if(n && is(n, ss)){
5704                         r[++ri] = ci;
5705                     }
5706                 }
5707                 return r;
5708             }
5709         }
5710     };
5711 }();
5712
5713 /**
5714  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5715  * @param {String} path The selector/xpath query
5716  * @param {Node} root (optional) The start of the query (defaults to document).
5717  * @return {Array}
5718  * @member Roo
5719  * @method query
5720  */
5721 Roo.query = Roo.DomQuery.select;
5722 /*
5723  * Based on:
5724  * Ext JS Library 1.1.1
5725  * Copyright(c) 2006-2007, Ext JS, LLC.
5726  *
5727  * Originally Released Under LGPL - original licence link has changed is not relivant.
5728  *
5729  * Fork - LGPL
5730  * <script type="text/javascript">
5731  */
5732
5733 /**
5734  * @class Roo.util.Observable
5735  * Base class that provides a common interface for publishing events. Subclasses are expected to
5736  * to have a property "events" with all the events defined.<br>
5737  * For example:
5738  * <pre><code>
5739  Employee = function(name){
5740     this.name = name;
5741     this.addEvents({
5742         "fired" : true,
5743         "quit" : true
5744     });
5745  }
5746  Roo.extend(Employee, Roo.util.Observable);
5747 </code></pre>
5748  * @param {Object} config properties to use (incuding events / listeners)
5749  */
5750
5751 Roo.util.Observable = function(cfg){
5752     
5753     cfg = cfg|| {};
5754     this.addEvents(cfg.events || {});
5755     if (cfg.events) {
5756         delete cfg.events; // make sure
5757     }
5758      
5759     Roo.apply(this, cfg);
5760     
5761     if(this.listeners){
5762         this.on(this.listeners);
5763         delete this.listeners;
5764     }
5765 };
5766 Roo.util.Observable.prototype = {
5767     /** 
5768  * @cfg {Object} listeners  list of events and functions to call for this object, 
5769  * For example :
5770  * <pre><code>
5771     listeners :  { 
5772        'click' : function(e) {
5773            ..... 
5774         } ,
5775         .... 
5776     } 
5777   </code></pre>
5778  */
5779     
5780     
5781     /**
5782      * Fires the specified event with the passed parameters (minus the event name).
5783      * @param {String} eventName
5784      * @param {Object...} args Variable number of parameters are passed to handlers
5785      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5786      */
5787     fireEvent : function(){
5788         var ce = this.events[arguments[0].toLowerCase()];
5789         if(typeof ce == "object"){
5790             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5791         }else{
5792             return true;
5793         }
5794     },
5795
5796     // private
5797     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5798
5799     /**
5800      * Appends an event handler to this component
5801      * @param {String}   eventName The type of event to listen for
5802      * @param {Function} handler The method the event invokes
5803      * @param {Object}   scope (optional) The scope in which to execute the handler
5804      * function. The handler function's "this" context.
5805      * @param {Object}   options (optional) An object containing handler configuration
5806      * properties. This may contain any of the following properties:<ul>
5807      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5808      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5809      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5810      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5811      * by the specified number of milliseconds. If the event fires again within that time, the original
5812      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5813      * </ul><br>
5814      * <p>
5815      * <b>Combining Options</b><br>
5816      * Using the options argument, it is possible to combine different types of listeners:<br>
5817      * <br>
5818      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5819                 <pre><code>
5820                 el.on('click', this.onClick, this, {
5821                         single: true,
5822                 delay: 100,
5823                 forumId: 4
5824                 });
5825                 </code></pre>
5826      * <p>
5827      * <b>Attaching multiple handlers in 1 call</b><br>
5828      * The method also allows for a single argument to be passed which is a config object containing properties
5829      * which specify multiple handlers.
5830      * <pre><code>
5831                 el.on({
5832                         'click': {
5833                         fn: this.onClick,
5834                         scope: this,
5835                         delay: 100
5836                 }, 
5837                 'mouseover': {
5838                         fn: this.onMouseOver,
5839                         scope: this
5840                 },
5841                 'mouseout': {
5842                         fn: this.onMouseOut,
5843                         scope: this
5844                 }
5845                 });
5846                 </code></pre>
5847      * <p>
5848      * Or a shorthand syntax which passes the same scope object to all handlers:
5849         <pre><code>
5850                 el.on({
5851                         'click': this.onClick,
5852                 'mouseover': this.onMouseOver,
5853                 'mouseout': this.onMouseOut,
5854                 scope: this
5855                 });
5856                 </code></pre>
5857      */
5858     addListener : function(eventName, fn, scope, o){
5859         if(typeof eventName == "object"){
5860             o = eventName;
5861             for(var e in o){
5862                 if(this.filterOptRe.test(e)){
5863                     continue;
5864                 }
5865                 if(typeof o[e] == "function"){
5866                     // shared options
5867                     this.addListener(e, o[e], o.scope,  o);
5868                 }else{
5869                     // individual options
5870                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5871                 }
5872             }
5873             return;
5874         }
5875         o = (!o || typeof o == "boolean") ? {} : o;
5876         eventName = eventName.toLowerCase();
5877         var ce = this.events[eventName] || true;
5878         if(typeof ce == "boolean"){
5879             ce = new Roo.util.Event(this, eventName);
5880             this.events[eventName] = ce;
5881         }
5882         ce.addListener(fn, scope, o);
5883     },
5884
5885     /**
5886      * Removes a listener
5887      * @param {String}   eventName     The type of event to listen for
5888      * @param {Function} handler        The handler to remove
5889      * @param {Object}   scope  (optional) The scope (this object) for the handler
5890      */
5891     removeListener : function(eventName, fn, scope){
5892         var ce = this.events[eventName.toLowerCase()];
5893         if(typeof ce == "object"){
5894             ce.removeListener(fn, scope);
5895         }
5896     },
5897
5898     /**
5899      * Removes all listeners for this object
5900      */
5901     purgeListeners : function(){
5902         for(var evt in this.events){
5903             if(typeof this.events[evt] == "object"){
5904                  this.events[evt].clearListeners();
5905             }
5906         }
5907     },
5908
5909     relayEvents : function(o, events){
5910         var createHandler = function(ename){
5911             return function(){
5912                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5913             };
5914         };
5915         for(var i = 0, len = events.length; i < len; i++){
5916             var ename = events[i];
5917             if(!this.events[ename]){ this.events[ename] = true; };
5918             o.on(ename, createHandler(ename), this);
5919         }
5920     },
5921
5922     /**
5923      * Used to define events on this Observable
5924      * @param {Object} object The object with the events defined
5925      */
5926     addEvents : function(o){
5927         if(!this.events){
5928             this.events = {};
5929         }
5930         Roo.applyIf(this.events, o);
5931     },
5932
5933     /**
5934      * Checks to see if this object has any listeners for a specified event
5935      * @param {String} eventName The name of the event to check for
5936      * @return {Boolean} True if the event is being listened for, else false
5937      */
5938     hasListener : function(eventName){
5939         var e = this.events[eventName];
5940         return typeof e == "object" && e.listeners.length > 0;
5941     }
5942 };
5943 /**
5944  * Appends an event handler to this element (shorthand for addListener)
5945  * @param {String}   eventName     The type of event to listen for
5946  * @param {Function} handler        The method the event invokes
5947  * @param {Object}   scope (optional) The scope in which to execute the handler
5948  * function. The handler function's "this" context.
5949  * @param {Object}   options  (optional)
5950  * @method
5951  */
5952 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5953 /**
5954  * Removes a listener (shorthand for removeListener)
5955  * @param {String}   eventName     The type of event to listen for
5956  * @param {Function} handler        The handler to remove
5957  * @param {Object}   scope  (optional) The scope (this object) for the handler
5958  * @method
5959  */
5960 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5961
5962 /**
5963  * Starts capture on the specified Observable. All events will be passed
5964  * to the supplied function with the event name + standard signature of the event
5965  * <b>before</b> the event is fired. If the supplied function returns false,
5966  * the event will not fire.
5967  * @param {Observable} o The Observable to capture
5968  * @param {Function} fn The function to call
5969  * @param {Object} scope (optional) The scope (this object) for the fn
5970  * @static
5971  */
5972 Roo.util.Observable.capture = function(o, fn, scope){
5973     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5974 };
5975
5976 /**
5977  * Removes <b>all</b> added captures from the Observable.
5978  * @param {Observable} o The Observable to release
5979  * @static
5980  */
5981 Roo.util.Observable.releaseCapture = function(o){
5982     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5983 };
5984
5985 (function(){
5986
5987     var createBuffered = function(h, o, scope){
5988         var task = new Roo.util.DelayedTask();
5989         return function(){
5990             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5991         };
5992     };
5993
5994     var createSingle = function(h, e, fn, scope){
5995         return function(){
5996             e.removeListener(fn, scope);
5997             return h.apply(scope, arguments);
5998         };
5999     };
6000
6001     var createDelayed = function(h, o, scope){
6002         return function(){
6003             var args = Array.prototype.slice.call(arguments, 0);
6004             setTimeout(function(){
6005                 h.apply(scope, args);
6006             }, o.delay || 10);
6007         };
6008     };
6009
6010     Roo.util.Event = function(obj, name){
6011         this.name = name;
6012         this.obj = obj;
6013         this.listeners = [];
6014     };
6015
6016     Roo.util.Event.prototype = {
6017         addListener : function(fn, scope, options){
6018             var o = options || {};
6019             scope = scope || this.obj;
6020             if(!this.isListening(fn, scope)){
6021                 var l = {fn: fn, scope: scope, options: o};
6022                 var h = fn;
6023                 if(o.delay){
6024                     h = createDelayed(h, o, scope);
6025                 }
6026                 if(o.single){
6027                     h = createSingle(h, this, fn, scope);
6028                 }
6029                 if(o.buffer){
6030                     h = createBuffered(h, o, scope);
6031                 }
6032                 l.fireFn = h;
6033                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6034                     this.listeners.push(l);
6035                 }else{
6036                     this.listeners = this.listeners.slice(0);
6037                     this.listeners.push(l);
6038                 }
6039             }
6040         },
6041
6042         findListener : function(fn, scope){
6043             scope = scope || this.obj;
6044             var ls = this.listeners;
6045             for(var i = 0, len = ls.length; i < len; i++){
6046                 var l = ls[i];
6047                 if(l.fn == fn && l.scope == scope){
6048                     return i;
6049                 }
6050             }
6051             return -1;
6052         },
6053
6054         isListening : function(fn, scope){
6055             return this.findListener(fn, scope) != -1;
6056         },
6057
6058         removeListener : function(fn, scope){
6059             var index;
6060             if((index = this.findListener(fn, scope)) != -1){
6061                 if(!this.firing){
6062                     this.listeners.splice(index, 1);
6063                 }else{
6064                     this.listeners = this.listeners.slice(0);
6065                     this.listeners.splice(index, 1);
6066                 }
6067                 return true;
6068             }
6069             return false;
6070         },
6071
6072         clearListeners : function(){
6073             this.listeners = [];
6074         },
6075
6076         fire : function(){
6077             var ls = this.listeners, scope, len = ls.length;
6078             if(len > 0){
6079                 this.firing = true;
6080                 var args = Array.prototype.slice.call(arguments, 0);
6081                 for(var i = 0; i < len; i++){
6082                     var l = ls[i];
6083                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6084                         this.firing = false;
6085                         return false;
6086                     }
6087                 }
6088                 this.firing = false;
6089             }
6090             return true;
6091         }
6092     };
6093 })();/*
6094  * RooJS Library 
6095  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6096  *
6097  * Licence LGPL 
6098  *
6099  */
6100  
6101 /**
6102  * @class Roo.Document
6103  * @extends Roo.util.Observable
6104  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6105  * 
6106  * @param {Object} config the methods and properties of the 'base' class for the application.
6107  * 
6108  *  Generic Page handler - implement this to start your app..
6109  * 
6110  * eg.
6111  *  MyProject = new Roo.Document({
6112         events : {
6113             'load' : true // your events..
6114         },
6115         listeners : {
6116             'ready' : function() {
6117                 // fired on Roo.onReady()
6118             }
6119         }
6120  * 
6121  */
6122 Roo.Document = function(cfg) {
6123      
6124     this.addEvents({ 
6125         'ready' : true
6126     });
6127     Roo.util.Observable.call(this,cfg);
6128     
6129     var _this = this;
6130     
6131     Roo.onReady(function() {
6132         _this.fireEvent('ready');
6133     },null,false);
6134     
6135     
6136 }
6137
6138 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6139  * Based on:
6140  * Ext JS Library 1.1.1
6141  * Copyright(c) 2006-2007, Ext JS, LLC.
6142  *
6143  * Originally Released Under LGPL - original licence link has changed is not relivant.
6144  *
6145  * Fork - LGPL
6146  * <script type="text/javascript">
6147  */
6148
6149 /**
6150  * @class Roo.EventManager
6151  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6152  * several useful events directly.
6153  * See {@link Roo.EventObject} for more details on normalized event objects.
6154  * @singleton
6155  */
6156 Roo.EventManager = function(){
6157     var docReadyEvent, docReadyProcId, docReadyState = false;
6158     var resizeEvent, resizeTask, textEvent, textSize;
6159     var E = Roo.lib.Event;
6160     var D = Roo.lib.Dom;
6161
6162     
6163     
6164
6165     var fireDocReady = function(){
6166         if(!docReadyState){
6167             docReadyState = true;
6168             Roo.isReady = true;
6169             if(docReadyProcId){
6170                 clearInterval(docReadyProcId);
6171             }
6172             if(Roo.isGecko || Roo.isOpera) {
6173                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6174             }
6175             if(Roo.isIE){
6176                 var defer = document.getElementById("ie-deferred-loader");
6177                 if(defer){
6178                     defer.onreadystatechange = null;
6179                     defer.parentNode.removeChild(defer);
6180                 }
6181             }
6182             if(docReadyEvent){
6183                 docReadyEvent.fire();
6184                 docReadyEvent.clearListeners();
6185             }
6186         }
6187     };
6188     
6189     var initDocReady = function(){
6190         docReadyEvent = new Roo.util.Event();
6191         if(Roo.isGecko || Roo.isOpera) {
6192             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6193         }else if(Roo.isIE){
6194             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6195             var defer = document.getElementById("ie-deferred-loader");
6196             defer.onreadystatechange = function(){
6197                 if(this.readyState == "complete"){
6198                     fireDocReady();
6199                 }
6200             };
6201         }else if(Roo.isSafari){ 
6202             docReadyProcId = setInterval(function(){
6203                 var rs = document.readyState;
6204                 if(rs == "complete") {
6205                     fireDocReady();     
6206                  }
6207             }, 10);
6208         }
6209         // no matter what, make sure it fires on load
6210         E.on(window, "load", fireDocReady);
6211     };
6212
6213     var createBuffered = function(h, o){
6214         var task = new Roo.util.DelayedTask(h);
6215         return function(e){
6216             // create new event object impl so new events don't wipe out properties
6217             e = new Roo.EventObjectImpl(e);
6218             task.delay(o.buffer, h, null, [e]);
6219         };
6220     };
6221
6222     var createSingle = function(h, el, ename, fn){
6223         return function(e){
6224             Roo.EventManager.removeListener(el, ename, fn);
6225             h(e);
6226         };
6227     };
6228
6229     var createDelayed = function(h, o){
6230         return function(e){
6231             // create new event object impl so new events don't wipe out properties
6232             e = new Roo.EventObjectImpl(e);
6233             setTimeout(function(){
6234                 h(e);
6235             }, o.delay || 10);
6236         };
6237     };
6238     var transitionEndVal = false;
6239     
6240     var transitionEnd = function()
6241     {
6242         if (transitionEndVal) {
6243             return transitionEndVal;
6244         }
6245         var el = document.createElement('div');
6246
6247         var transEndEventNames = {
6248             WebkitTransition : 'webkitTransitionEnd',
6249             MozTransition    : 'transitionend',
6250             OTransition      : 'oTransitionEnd otransitionend',
6251             transition       : 'transitionend'
6252         };
6253     
6254         for (var name in transEndEventNames) {
6255             if (el.style[name] !== undefined) {
6256                 transitionEndVal = transEndEventNames[name];
6257                 return  transitionEndVal ;
6258             }
6259         }
6260     }
6261     
6262
6263     var listen = function(element, ename, opt, fn, scope){
6264         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6265         fn = fn || o.fn; scope = scope || o.scope;
6266         var el = Roo.getDom(element);
6267         
6268         
6269         if(!el){
6270             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6271         }
6272         
6273         if (ename == 'transitionend') {
6274             ename = transitionEnd();
6275         }
6276         var h = function(e){
6277             e = Roo.EventObject.setEvent(e);
6278             var t;
6279             if(o.delegate){
6280                 t = e.getTarget(o.delegate, el);
6281                 if(!t){
6282                     return;
6283                 }
6284             }else{
6285                 t = e.target;
6286             }
6287             if(o.stopEvent === true){
6288                 e.stopEvent();
6289             }
6290             if(o.preventDefault === true){
6291                e.preventDefault();
6292             }
6293             if(o.stopPropagation === true){
6294                 e.stopPropagation();
6295             }
6296
6297             if(o.normalized === false){
6298                 e = e.browserEvent;
6299             }
6300
6301             fn.call(scope || el, e, t, o);
6302         };
6303         if(o.delay){
6304             h = createDelayed(h, o);
6305         }
6306         if(o.single){
6307             h = createSingle(h, el, ename, fn);
6308         }
6309         if(o.buffer){
6310             h = createBuffered(h, o);
6311         }
6312         
6313         fn._handlers = fn._handlers || [];
6314         
6315         
6316         fn._handlers.push([Roo.id(el), ename, h]);
6317         
6318         
6319          
6320         E.on(el, ename, h);
6321         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6322             el.addEventListener("DOMMouseScroll", h, false);
6323             E.on(window, 'unload', function(){
6324                 el.removeEventListener("DOMMouseScroll", h, false);
6325             });
6326         }
6327         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6328             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6329         }
6330         return h;
6331     };
6332
6333     var stopListening = function(el, ename, fn){
6334         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6335         if(hds){
6336             for(var i = 0, len = hds.length; i < len; i++){
6337                 var h = hds[i];
6338                 if(h[0] == id && h[1] == ename){
6339                     hd = h[2];
6340                     hds.splice(i, 1);
6341                     break;
6342                 }
6343             }
6344         }
6345         E.un(el, ename, hd);
6346         el = Roo.getDom(el);
6347         if(ename == "mousewheel" && el.addEventListener){
6348             el.removeEventListener("DOMMouseScroll", hd, false);
6349         }
6350         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6351             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6352         }
6353     };
6354
6355     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6356     
6357     var pub = {
6358         
6359         
6360         /** 
6361          * Fix for doc tools
6362          * @scope Roo.EventManager
6363          */
6364         
6365         
6366         /** 
6367          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6368          * object with a Roo.EventObject
6369          * @param {Function} fn        The method the event invokes
6370          * @param {Object}   scope    An object that becomes the scope of the handler
6371          * @param {boolean}  override If true, the obj passed in becomes
6372          *                             the execution scope of the listener
6373          * @return {Function} The wrapped function
6374          * @deprecated
6375          */
6376         wrap : function(fn, scope, override){
6377             return function(e){
6378                 Roo.EventObject.setEvent(e);
6379                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6380             };
6381         },
6382         
6383         /**
6384      * Appends an event handler to an element (shorthand for addListener)
6385      * @param {String/HTMLElement}   element        The html element or id to assign the
6386      * @param {String}   eventName The type of event to listen for
6387      * @param {Function} handler The method the event invokes
6388      * @param {Object}   scope (optional) The scope in which to execute the handler
6389      * function. The handler function's "this" context.
6390      * @param {Object}   options (optional) An object containing handler configuration
6391      * properties. This may contain any of the following properties:<ul>
6392      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6393      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6394      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6395      * <li>preventDefault {Boolean} True to prevent the default action</li>
6396      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6397      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6398      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6399      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6400      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6401      * by the specified number of milliseconds. If the event fires again within that time, the original
6402      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6403      * </ul><br>
6404      * <p>
6405      * <b>Combining Options</b><br>
6406      * Using the options argument, it is possible to combine different types of listeners:<br>
6407      * <br>
6408      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6409      * Code:<pre><code>
6410 el.on('click', this.onClick, this, {
6411     single: true,
6412     delay: 100,
6413     stopEvent : true,
6414     forumId: 4
6415 });</code></pre>
6416      * <p>
6417      * <b>Attaching multiple handlers in 1 call</b><br>
6418       * The method also allows for a single argument to be passed which is a config object containing properties
6419      * which specify multiple handlers.
6420      * <p>
6421      * Code:<pre><code>
6422 el.on({
6423     'click' : {
6424         fn: this.onClick
6425         scope: this,
6426         delay: 100
6427     },
6428     'mouseover' : {
6429         fn: this.onMouseOver
6430         scope: this
6431     },
6432     'mouseout' : {
6433         fn: this.onMouseOut
6434         scope: this
6435     }
6436 });</code></pre>
6437      * <p>
6438      * Or a shorthand syntax:<br>
6439      * Code:<pre><code>
6440 el.on({
6441     'click' : this.onClick,
6442     'mouseover' : this.onMouseOver,
6443     'mouseout' : this.onMouseOut
6444     scope: this
6445 });</code></pre>
6446      */
6447         addListener : function(element, eventName, fn, scope, options){
6448             if(typeof eventName == "object"){
6449                 var o = eventName;
6450                 for(var e in o){
6451                     if(propRe.test(e)){
6452                         continue;
6453                     }
6454                     if(typeof o[e] == "function"){
6455                         // shared options
6456                         listen(element, e, o, o[e], o.scope);
6457                     }else{
6458                         // individual options
6459                         listen(element, e, o[e]);
6460                     }
6461                 }
6462                 return;
6463             }
6464             return listen(element, eventName, options, fn, scope);
6465         },
6466         
6467         /**
6468          * Removes an event handler
6469          *
6470          * @param {String/HTMLElement}   element        The id or html element to remove the 
6471          *                             event from
6472          * @param {String}   eventName     The type of event
6473          * @param {Function} fn
6474          * @return {Boolean} True if a listener was actually removed
6475          */
6476         removeListener : function(element, eventName, fn){
6477             return stopListening(element, eventName, fn);
6478         },
6479         
6480         /**
6481          * Fires when the document is ready (before onload and before images are loaded). Can be 
6482          * accessed shorthanded Roo.onReady().
6483          * @param {Function} fn        The method the event invokes
6484          * @param {Object}   scope    An  object that becomes the scope of the handler
6485          * @param {boolean}  options
6486          */
6487         onDocumentReady : function(fn, scope, options){
6488             if(docReadyState){ // if it already fired
6489                 docReadyEvent.addListener(fn, scope, options);
6490                 docReadyEvent.fire();
6491                 docReadyEvent.clearListeners();
6492                 return;
6493             }
6494             if(!docReadyEvent){
6495                 initDocReady();
6496             }
6497             docReadyEvent.addListener(fn, scope, options);
6498         },
6499         
6500         /**
6501          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6502          * @param {Function} fn        The method the event invokes
6503          * @param {Object}   scope    An object that becomes the scope of the handler
6504          * @param {boolean}  options
6505          */
6506         onWindowResize : function(fn, scope, options){
6507             if(!resizeEvent){
6508                 resizeEvent = new Roo.util.Event();
6509                 resizeTask = new Roo.util.DelayedTask(function(){
6510                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6511                 });
6512                 E.on(window, "resize", function(){
6513                     if(Roo.isIE){
6514                         resizeTask.delay(50);
6515                     }else{
6516                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6517                     }
6518                 });
6519             }
6520             resizeEvent.addListener(fn, scope, options);
6521         },
6522
6523         /**
6524          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
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         onTextResize : function(fn, scope, options){
6530             if(!textEvent){
6531                 textEvent = new Roo.util.Event();
6532                 var textEl = new Roo.Element(document.createElement('div'));
6533                 textEl.dom.className = 'x-text-resize';
6534                 textEl.dom.innerHTML = 'X';
6535                 textEl.appendTo(document.body);
6536                 textSize = textEl.dom.offsetHeight;
6537                 setInterval(function(){
6538                     if(textEl.dom.offsetHeight != textSize){
6539                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6540                     }
6541                 }, this.textResizeInterval);
6542             }
6543             textEvent.addListener(fn, scope, options);
6544         },
6545
6546         /**
6547          * Removes the passed window resize listener.
6548          * @param {Function} fn        The method the event invokes
6549          * @param {Object}   scope    The scope of handler
6550          */
6551         removeResizeListener : function(fn, scope){
6552             if(resizeEvent){
6553                 resizeEvent.removeListener(fn, scope);
6554             }
6555         },
6556
6557         // private
6558         fireResize : function(){
6559             if(resizeEvent){
6560                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6561             }   
6562         },
6563         /**
6564          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6565          */
6566         ieDeferSrc : false,
6567         /**
6568          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6569          */
6570         textResizeInterval : 50
6571     };
6572     
6573     /**
6574      * Fix for doc tools
6575      * @scopeAlias pub=Roo.EventManager
6576      */
6577     
6578      /**
6579      * Appends an event handler to an element (shorthand for addListener)
6580      * @param {String/HTMLElement}   element        The html element or id to assign the
6581      * @param {String}   eventName The type of event to listen for
6582      * @param {Function} handler The method the event invokes
6583      * @param {Object}   scope (optional) The scope in which to execute the handler
6584      * function. The handler function's "this" context.
6585      * @param {Object}   options (optional) An object containing handler configuration
6586      * properties. This may contain any of the following properties:<ul>
6587      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6588      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6589      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6590      * <li>preventDefault {Boolean} True to prevent the default action</li>
6591      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6592      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6593      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6594      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6595      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6596      * by the specified number of milliseconds. If the event fires again within that time, the original
6597      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6598      * </ul><br>
6599      * <p>
6600      * <b>Combining Options</b><br>
6601      * Using the options argument, it is possible to combine different types of listeners:<br>
6602      * <br>
6603      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6604      * Code:<pre><code>
6605 el.on('click', this.onClick, this, {
6606     single: true,
6607     delay: 100,
6608     stopEvent : true,
6609     forumId: 4
6610 });</code></pre>
6611      * <p>
6612      * <b>Attaching multiple handlers in 1 call</b><br>
6613       * The method also allows for a single argument to be passed which is a config object containing properties
6614      * which specify multiple handlers.
6615      * <p>
6616      * Code:<pre><code>
6617 el.on({
6618     'click' : {
6619         fn: this.onClick
6620         scope: this,
6621         delay: 100
6622     },
6623     'mouseover' : {
6624         fn: this.onMouseOver
6625         scope: this
6626     },
6627     'mouseout' : {
6628         fn: this.onMouseOut
6629         scope: this
6630     }
6631 });</code></pre>
6632      * <p>
6633      * Or a shorthand syntax:<br>
6634      * Code:<pre><code>
6635 el.on({
6636     'click' : this.onClick,
6637     'mouseover' : this.onMouseOver,
6638     'mouseout' : this.onMouseOut
6639     scope: this
6640 });</code></pre>
6641      */
6642     pub.on = pub.addListener;
6643     pub.un = pub.removeListener;
6644
6645     pub.stoppedMouseDownEvent = new Roo.util.Event();
6646     return pub;
6647 }();
6648 /**
6649   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6650   * @param {Function} fn        The method the event invokes
6651   * @param {Object}   scope    An  object that becomes the scope of the handler
6652   * @param {boolean}  override If true, the obj passed in becomes
6653   *                             the execution scope of the listener
6654   * @member Roo
6655   * @method onReady
6656  */
6657 Roo.onReady = Roo.EventManager.onDocumentReady;
6658
6659 Roo.onReady(function(){
6660     var bd = Roo.get(document.body);
6661     if(!bd){ return; }
6662
6663     var cls = [
6664             Roo.isIE ? "roo-ie"
6665             : Roo.isIE11 ? "roo-ie11"
6666             : Roo.isEdge ? "roo-edge"
6667             : Roo.isGecko ? "roo-gecko"
6668             : Roo.isOpera ? "roo-opera"
6669             : Roo.isSafari ? "roo-safari" : ""];
6670
6671     if(Roo.isMac){
6672         cls.push("roo-mac");
6673     }
6674     if(Roo.isLinux){
6675         cls.push("roo-linux");
6676     }
6677     if(Roo.isIOS){
6678         cls.push("roo-ios");
6679     }
6680     if(Roo.isTouch){
6681         cls.push("roo-touch");
6682     }
6683     if(Roo.isBorderBox){
6684         cls.push('roo-border-box');
6685     }
6686     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6687         var p = bd.dom.parentNode;
6688         if(p){
6689             p.className += ' roo-strict';
6690         }
6691     }
6692     bd.addClass(cls.join(' '));
6693 });
6694
6695 /**
6696  * @class Roo.EventObject
6697  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6698  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6699  * Example:
6700  * <pre><code>
6701  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6702     e.preventDefault();
6703     var target = e.getTarget();
6704     ...
6705  }
6706  var myDiv = Roo.get("myDiv");
6707  myDiv.on("click", handleClick);
6708  //or
6709  Roo.EventManager.on("myDiv", 'click', handleClick);
6710  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6711  </code></pre>
6712  * @singleton
6713  */
6714 Roo.EventObject = function(){
6715     
6716     var E = Roo.lib.Event;
6717     
6718     // safari keypress events for special keys return bad keycodes
6719     var safariKeys = {
6720         63234 : 37, // left
6721         63235 : 39, // right
6722         63232 : 38, // up
6723         63233 : 40, // down
6724         63276 : 33, // page up
6725         63277 : 34, // page down
6726         63272 : 46, // delete
6727         63273 : 36, // home
6728         63275 : 35  // end
6729     };
6730
6731     // normalize button clicks
6732     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6733                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6734
6735     Roo.EventObjectImpl = function(e){
6736         if(e){
6737             this.setEvent(e.browserEvent || e);
6738         }
6739     };
6740     Roo.EventObjectImpl.prototype = {
6741         /**
6742          * Used to fix doc tools.
6743          * @scope Roo.EventObject.prototype
6744          */
6745             
6746
6747         
6748         
6749         /** The normal browser event */
6750         browserEvent : null,
6751         /** The button pressed in a mouse event */
6752         button : -1,
6753         /** True if the shift key was down during the event */
6754         shiftKey : false,
6755         /** True if the control key was down during the event */
6756         ctrlKey : false,
6757         /** True if the alt key was down during the event */
6758         altKey : false,
6759
6760         /** Key constant 
6761         * @type Number */
6762         BACKSPACE : 8,
6763         /** Key constant 
6764         * @type Number */
6765         TAB : 9,
6766         /** Key constant 
6767         * @type Number */
6768         RETURN : 13,
6769         /** Key constant 
6770         * @type Number */
6771         ENTER : 13,
6772         /** Key constant 
6773         * @type Number */
6774         SHIFT : 16,
6775         /** Key constant 
6776         * @type Number */
6777         CONTROL : 17,
6778         /** Key constant 
6779         * @type Number */
6780         ESC : 27,
6781         /** Key constant 
6782         * @type Number */
6783         SPACE : 32,
6784         /** Key constant 
6785         * @type Number */
6786         PAGEUP : 33,
6787         /** Key constant 
6788         * @type Number */
6789         PAGEDOWN : 34,
6790         /** Key constant 
6791         * @type Number */
6792         END : 35,
6793         /** Key constant 
6794         * @type Number */
6795         HOME : 36,
6796         /** Key constant 
6797         * @type Number */
6798         LEFT : 37,
6799         /** Key constant 
6800         * @type Number */
6801         UP : 38,
6802         /** Key constant 
6803         * @type Number */
6804         RIGHT : 39,
6805         /** Key constant 
6806         * @type Number */
6807         DOWN : 40,
6808         /** Key constant 
6809         * @type Number */
6810         DELETE : 46,
6811         /** Key constant 
6812         * @type Number */
6813         F5 : 116,
6814
6815            /** @private */
6816         setEvent : function(e){
6817             if(e == this || (e && e.browserEvent)){ // already wrapped
6818                 return e;
6819             }
6820             this.browserEvent = e;
6821             if(e){
6822                 // normalize buttons
6823                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6824                 if(e.type == 'click' && this.button == -1){
6825                     this.button = 0;
6826                 }
6827                 this.type = e.type;
6828                 this.shiftKey = e.shiftKey;
6829                 // mac metaKey behaves like ctrlKey
6830                 this.ctrlKey = e.ctrlKey || e.metaKey;
6831                 this.altKey = e.altKey;
6832                 // in getKey these will be normalized for the mac
6833                 this.keyCode = e.keyCode;
6834                 // keyup warnings on firefox.
6835                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6836                 // cache the target for the delayed and or buffered events
6837                 this.target = E.getTarget(e);
6838                 // same for XY
6839                 this.xy = E.getXY(e);
6840             }else{
6841                 this.button = -1;
6842                 this.shiftKey = false;
6843                 this.ctrlKey = false;
6844                 this.altKey = false;
6845                 this.keyCode = 0;
6846                 this.charCode =0;
6847                 this.target = null;
6848                 this.xy = [0, 0];
6849             }
6850             return this;
6851         },
6852
6853         /**
6854          * Stop the event (preventDefault and stopPropagation)
6855          */
6856         stopEvent : function(){
6857             if(this.browserEvent){
6858                 if(this.browserEvent.type == 'mousedown'){
6859                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6860                 }
6861                 E.stopEvent(this.browserEvent);
6862             }
6863         },
6864
6865         /**
6866          * Prevents the browsers default handling of the event.
6867          */
6868         preventDefault : function(){
6869             if(this.browserEvent){
6870                 E.preventDefault(this.browserEvent);
6871             }
6872         },
6873
6874         /** @private */
6875         isNavKeyPress : function(){
6876             var k = this.keyCode;
6877             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6878             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6879         },
6880
6881         isSpecialKey : function(){
6882             var k = this.keyCode;
6883             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6884             (k == 16) || (k == 17) ||
6885             (k >= 18 && k <= 20) ||
6886             (k >= 33 && k <= 35) ||
6887             (k >= 36 && k <= 39) ||
6888             (k >= 44 && k <= 45);
6889         },
6890         /**
6891          * Cancels bubbling of the event.
6892          */
6893         stopPropagation : function(){
6894             if(this.browserEvent){
6895                 if(this.type == 'mousedown'){
6896                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6897                 }
6898                 E.stopPropagation(this.browserEvent);
6899             }
6900         },
6901
6902         /**
6903          * Gets the key code for the event.
6904          * @return {Number}
6905          */
6906         getCharCode : function(){
6907             return this.charCode || this.keyCode;
6908         },
6909
6910         /**
6911          * Returns a normalized keyCode for the event.
6912          * @return {Number} The key code
6913          */
6914         getKey : function(){
6915             var k = this.keyCode || this.charCode;
6916             return Roo.isSafari ? (safariKeys[k] || k) : k;
6917         },
6918
6919         /**
6920          * Gets the x coordinate of the event.
6921          * @return {Number}
6922          */
6923         getPageX : function(){
6924             return this.xy[0];
6925         },
6926
6927         /**
6928          * Gets the y coordinate of the event.
6929          * @return {Number}
6930          */
6931         getPageY : function(){
6932             return this.xy[1];
6933         },
6934
6935         /**
6936          * Gets the time of the event.
6937          * @return {Number}
6938          */
6939         getTime : function(){
6940             if(this.browserEvent){
6941                 return E.getTime(this.browserEvent);
6942             }
6943             return null;
6944         },
6945
6946         /**
6947          * Gets the page coordinates of the event.
6948          * @return {Array} The xy values like [x, y]
6949          */
6950         getXY : function(){
6951             return this.xy;
6952         },
6953
6954         /**
6955          * Gets the target for the event.
6956          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6957          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6958                 search as a number or element (defaults to 10 || document.body)
6959          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6960          * @return {HTMLelement}
6961          */
6962         getTarget : function(selector, maxDepth, returnEl){
6963             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6964         },
6965         /**
6966          * Gets the related target.
6967          * @return {HTMLElement}
6968          */
6969         getRelatedTarget : function(){
6970             if(this.browserEvent){
6971                 return E.getRelatedTarget(this.browserEvent);
6972             }
6973             return null;
6974         },
6975
6976         /**
6977          * Normalizes mouse wheel delta across browsers
6978          * @return {Number} The delta
6979          */
6980         getWheelDelta : function(){
6981             var e = this.browserEvent;
6982             var delta = 0;
6983             if(e.wheelDelta){ /* IE/Opera. */
6984                 delta = e.wheelDelta/120;
6985             }else if(e.detail){ /* Mozilla case. */
6986                 delta = -e.detail/3;
6987             }
6988             return delta;
6989         },
6990
6991         /**
6992          * Returns true if the control, meta, shift or alt key was pressed during this event.
6993          * @return {Boolean}
6994          */
6995         hasModifier : function(){
6996             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6997         },
6998
6999         /**
7000          * Returns true if the target of this event equals el or is a child of el
7001          * @param {String/HTMLElement/Element} el
7002          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7003          * @return {Boolean}
7004          */
7005         within : function(el, related){
7006             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7007             return t && Roo.fly(el).contains(t);
7008         },
7009
7010         getPoint : function(){
7011             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7012         }
7013     };
7014
7015     return new Roo.EventObjectImpl();
7016 }();
7017             
7018     /*
7019  * Based on:
7020  * Ext JS Library 1.1.1
7021  * Copyright(c) 2006-2007, Ext JS, LLC.
7022  *
7023  * Originally Released Under LGPL - original licence link has changed is not relivant.
7024  *
7025  * Fork - LGPL
7026  * <script type="text/javascript">
7027  */
7028
7029  
7030 // was in Composite Element!??!?!
7031  
7032 (function(){
7033     var D = Roo.lib.Dom;
7034     var E = Roo.lib.Event;
7035     var A = Roo.lib.Anim;
7036
7037     // local style camelizing for speed
7038     var propCache = {};
7039     var camelRe = /(-[a-z])/gi;
7040     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7041     var view = document.defaultView;
7042
7043 /**
7044  * @class Roo.Element
7045  * Represents an Element in the DOM.<br><br>
7046  * Usage:<br>
7047 <pre><code>
7048 var el = Roo.get("my-div");
7049
7050 // or with getEl
7051 var el = getEl("my-div");
7052
7053 // or with a DOM element
7054 var el = Roo.get(myDivElement);
7055 </code></pre>
7056  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7057  * each call instead of constructing a new one.<br><br>
7058  * <b>Animations</b><br />
7059  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7060  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7061 <pre>
7062 Option    Default   Description
7063 --------- --------  ---------------------------------------------
7064 duration  .35       The duration of the animation in seconds
7065 easing    easeOut   The YUI easing method
7066 callback  none      A function to execute when the anim completes
7067 scope     this      The scope (this) of the callback function
7068 </pre>
7069 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7070 * manipulate the animation. Here's an example:
7071 <pre><code>
7072 var el = Roo.get("my-div");
7073
7074 // no animation
7075 el.setWidth(100);
7076
7077 // default animation
7078 el.setWidth(100, true);
7079
7080 // animation with some options set
7081 el.setWidth(100, {
7082     duration: 1,
7083     callback: this.foo,
7084     scope: this
7085 });
7086
7087 // using the "anim" property to get the Anim object
7088 var opt = {
7089     duration: 1,
7090     callback: this.foo,
7091     scope: this
7092 };
7093 el.setWidth(100, opt);
7094 ...
7095 if(opt.anim.isAnimated()){
7096     opt.anim.stop();
7097 }
7098 </code></pre>
7099 * <b> Composite (Collections of) Elements</b><br />
7100  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7101  * @constructor Create a new Element directly.
7102  * @param {String/HTMLElement} element
7103  * @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).
7104  */
7105     Roo.Element = function(element, forceNew){
7106         var dom = typeof element == "string" ?
7107                 document.getElementById(element) : element;
7108         if(!dom){ // invalid id/element
7109             return null;
7110         }
7111         var id = dom.id;
7112         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7113             return Roo.Element.cache[id];
7114         }
7115
7116         /**
7117          * The DOM element
7118          * @type HTMLElement
7119          */
7120         this.dom = dom;
7121
7122         /**
7123          * The DOM element ID
7124          * @type String
7125          */
7126         this.id = id || Roo.id(dom);
7127     };
7128
7129     var El = Roo.Element;
7130
7131     El.prototype = {
7132         /**
7133          * The element's default display mode  (defaults to "")
7134          * @type String
7135          */
7136         originalDisplay : "",
7137
7138         visibilityMode : 1,
7139         /**
7140          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7141          * @type String
7142          */
7143         defaultUnit : "px",
7144         
7145         /**
7146          * Sets the element's visibility mode. When setVisible() is called it
7147          * will use this to determine whether to set the visibility or the display property.
7148          * @param visMode Element.VISIBILITY or Element.DISPLAY
7149          * @return {Roo.Element} this
7150          */
7151         setVisibilityMode : function(visMode){
7152             this.visibilityMode = visMode;
7153             return this;
7154         },
7155         /**
7156          * Convenience method for setVisibilityMode(Element.DISPLAY)
7157          * @param {String} display (optional) What to set display to when visible
7158          * @return {Roo.Element} this
7159          */
7160         enableDisplayMode : function(display){
7161             this.setVisibilityMode(El.DISPLAY);
7162             if(typeof display != "undefined") { this.originalDisplay = display; }
7163             return this;
7164         },
7165
7166         /**
7167          * 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)
7168          * @param {String} selector The simple selector to test
7169          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7170                 search as a number or element (defaults to 10 || document.body)
7171          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7172          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7173          */
7174         findParent : function(simpleSelector, maxDepth, returnEl){
7175             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7176             maxDepth = maxDepth || 50;
7177             if(typeof maxDepth != "number"){
7178                 stopEl = Roo.getDom(maxDepth);
7179                 maxDepth = 10;
7180             }
7181             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7182                 if(dq.is(p, simpleSelector)){
7183                     return returnEl ? Roo.get(p) : p;
7184                 }
7185                 depth++;
7186                 p = p.parentNode;
7187             }
7188             return null;
7189         },
7190
7191
7192         /**
7193          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7194          * @param {String} selector The simple selector to test
7195          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7196                 search as a number or element (defaults to 10 || document.body)
7197          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7198          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7199          */
7200         findParentNode : function(simpleSelector, maxDepth, returnEl){
7201             var p = Roo.fly(this.dom.parentNode, '_internal');
7202             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7203         },
7204         
7205         /**
7206          * Looks at  the scrollable parent element
7207          */
7208         findScrollableParent : function()
7209         {
7210             var overflowRegex = /(auto|scroll)/;
7211             
7212             if(this.getStyle('position') === 'fixed'){
7213                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7214             }
7215             
7216             var excludeStaticParent = this.getStyle('position') === "absolute";
7217             
7218             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7219                 
7220                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7221                     continue;
7222                 }
7223                 
7224                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7225                     return parent;
7226                 }
7227                 
7228                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7229                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7230                 }
7231             }
7232             
7233             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7234         },
7235
7236         /**
7237          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7238          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7239          * @param {String} selector The simple selector to test
7240          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7241                 search as a number or element (defaults to 10 || document.body)
7242          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7243          */
7244         up : function(simpleSelector, maxDepth){
7245             return this.findParentNode(simpleSelector, maxDepth, true);
7246         },
7247
7248
7249
7250         /**
7251          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7252          * @param {String} selector The simple selector to test
7253          * @return {Boolean} True if this element matches the selector, else false
7254          */
7255         is : function(simpleSelector){
7256             return Roo.DomQuery.is(this.dom, simpleSelector);
7257         },
7258
7259         /**
7260          * Perform animation on this element.
7261          * @param {Object} args The YUI animation control args
7262          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7263          * @param {Function} onComplete (optional) Function to call when animation completes
7264          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7265          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7266          * @return {Roo.Element} this
7267          */
7268         animate : function(args, duration, onComplete, easing, animType){
7269             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7270             return this;
7271         },
7272
7273         /*
7274          * @private Internal animation call
7275          */
7276         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7277             animType = animType || 'run';
7278             opt = opt || {};
7279             var anim = Roo.lib.Anim[animType](
7280                 this.dom, args,
7281                 (opt.duration || defaultDur) || .35,
7282                 (opt.easing || defaultEase) || 'easeOut',
7283                 function(){
7284                     Roo.callback(cb, this);
7285                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7286                 },
7287                 this
7288             );
7289             opt.anim = anim;
7290             return anim;
7291         },
7292
7293         // private legacy anim prep
7294         preanim : function(a, i){
7295             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7296         },
7297
7298         /**
7299          * Removes worthless text nodes
7300          * @param {Boolean} forceReclean (optional) By default the element
7301          * keeps track if it has been cleaned already so
7302          * you can call this over and over. However, if you update the element and
7303          * need to force a reclean, you can pass true.
7304          */
7305         clean : function(forceReclean){
7306             if(this.isCleaned && forceReclean !== true){
7307                 return this;
7308             }
7309             var ns = /\S/;
7310             var d = this.dom, n = d.firstChild, ni = -1;
7311             while(n){
7312                 var nx = n.nextSibling;
7313                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7314                     d.removeChild(n);
7315                 }else{
7316                     n.nodeIndex = ++ni;
7317                 }
7318                 n = nx;
7319             }
7320             this.isCleaned = true;
7321             return this;
7322         },
7323
7324         // private
7325         calcOffsetsTo : function(el){
7326             el = Roo.get(el);
7327             var d = el.dom;
7328             var restorePos = false;
7329             if(el.getStyle('position') == 'static'){
7330                 el.position('relative');
7331                 restorePos = true;
7332             }
7333             var x = 0, y =0;
7334             var op = this.dom;
7335             while(op && op != d && op.tagName != 'HTML'){
7336                 x+= op.offsetLeft;
7337                 y+= op.offsetTop;
7338                 op = op.offsetParent;
7339             }
7340             if(restorePos){
7341                 el.position('static');
7342             }
7343             return [x, y];
7344         },
7345
7346         /**
7347          * Scrolls this element into view within the passed container.
7348          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7349          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7350          * @return {Roo.Element} this
7351          */
7352         scrollIntoView : function(container, hscroll){
7353             var c = Roo.getDom(container) || document.body;
7354             var el = this.dom;
7355
7356             var o = this.calcOffsetsTo(c),
7357                 l = o[0],
7358                 t = o[1],
7359                 b = t+el.offsetHeight,
7360                 r = l+el.offsetWidth;
7361
7362             var ch = c.clientHeight;
7363             var ct = parseInt(c.scrollTop, 10);
7364             var cl = parseInt(c.scrollLeft, 10);
7365             var cb = ct + ch;
7366             var cr = cl + c.clientWidth;
7367
7368             if(t < ct){
7369                 c.scrollTop = t;
7370             }else if(b > cb){
7371                 c.scrollTop = b-ch;
7372             }
7373
7374             if(hscroll !== false){
7375                 if(l < cl){
7376                     c.scrollLeft = l;
7377                 }else if(r > cr){
7378                     c.scrollLeft = r-c.clientWidth;
7379                 }
7380             }
7381             return this;
7382         },
7383
7384         // private
7385         scrollChildIntoView : function(child, hscroll){
7386             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7387         },
7388
7389         /**
7390          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7391          * the new height may not be available immediately.
7392          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7393          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7394          * @param {Function} onComplete (optional) Function to call when animation completes
7395          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7396          * @return {Roo.Element} this
7397          */
7398         autoHeight : function(animate, duration, onComplete, easing){
7399             var oldHeight = this.getHeight();
7400             this.clip();
7401             this.setHeight(1); // force clipping
7402             setTimeout(function(){
7403                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7404                 if(!animate){
7405                     this.setHeight(height);
7406                     this.unclip();
7407                     if(typeof onComplete == "function"){
7408                         onComplete();
7409                     }
7410                 }else{
7411                     this.setHeight(oldHeight); // restore original height
7412                     this.setHeight(height, animate, duration, function(){
7413                         this.unclip();
7414                         if(typeof onComplete == "function") { onComplete(); }
7415                     }.createDelegate(this), easing);
7416                 }
7417             }.createDelegate(this), 0);
7418             return this;
7419         },
7420
7421         /**
7422          * Returns true if this element is an ancestor of the passed element
7423          * @param {HTMLElement/String} el The element to check
7424          * @return {Boolean} True if this element is an ancestor of el, else false
7425          */
7426         contains : function(el){
7427             if(!el){return false;}
7428             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7429         },
7430
7431         /**
7432          * Checks whether the element is currently visible using both visibility and display properties.
7433          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7434          * @return {Boolean} True if the element is currently visible, else false
7435          */
7436         isVisible : function(deep) {
7437             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7438             if(deep !== true || !vis){
7439                 return vis;
7440             }
7441             var p = this.dom.parentNode;
7442             while(p && p.tagName.toLowerCase() != "body"){
7443                 if(!Roo.fly(p, '_isVisible').isVisible()){
7444                     return false;
7445                 }
7446                 p = p.parentNode;
7447             }
7448             return true;
7449         },
7450
7451         /**
7452          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7453          * @param {String} selector The CSS selector
7454          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7455          * @return {CompositeElement/CompositeElementLite} The composite element
7456          */
7457         select : function(selector, unique){
7458             return El.select(selector, unique, this.dom);
7459         },
7460
7461         /**
7462          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7463          * @param {String} selector The CSS selector
7464          * @return {Array} An array of the matched nodes
7465          */
7466         query : function(selector, unique){
7467             return Roo.DomQuery.select(selector, this.dom);
7468         },
7469
7470         /**
7471          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7472          * @param {String} selector The CSS selector
7473          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7474          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7475          */
7476         child : function(selector, returnDom){
7477             var n = Roo.DomQuery.selectNode(selector, this.dom);
7478             return returnDom ? n : Roo.get(n);
7479         },
7480
7481         /**
7482          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7483          * @param {String} selector The CSS selector
7484          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7485          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7486          */
7487         down : function(selector, returnDom){
7488             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7489             return returnDom ? n : Roo.get(n);
7490         },
7491
7492         /**
7493          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7494          * @param {String} group The group the DD object is member of
7495          * @param {Object} config The DD config object
7496          * @param {Object} overrides An object containing methods to override/implement on the DD object
7497          * @return {Roo.dd.DD} The DD object
7498          */
7499         initDD : function(group, config, overrides){
7500             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7501             return Roo.apply(dd, overrides);
7502         },
7503
7504         /**
7505          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7506          * @param {String} group The group the DDProxy object is member of
7507          * @param {Object} config The DDProxy config object
7508          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7509          * @return {Roo.dd.DDProxy} The DDProxy object
7510          */
7511         initDDProxy : function(group, config, overrides){
7512             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7513             return Roo.apply(dd, overrides);
7514         },
7515
7516         /**
7517          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7518          * @param {String} group The group the DDTarget object is member of
7519          * @param {Object} config The DDTarget config object
7520          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7521          * @return {Roo.dd.DDTarget} The DDTarget object
7522          */
7523         initDDTarget : function(group, config, overrides){
7524             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7525             return Roo.apply(dd, overrides);
7526         },
7527
7528         /**
7529          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7530          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7531          * @param {Boolean} visible Whether the element is visible
7532          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7533          * @return {Roo.Element} this
7534          */
7535          setVisible : function(visible, animate){
7536             if(!animate || !A){
7537                 if(this.visibilityMode == El.DISPLAY){
7538                     this.setDisplayed(visible);
7539                 }else{
7540                     this.fixDisplay();
7541                     this.dom.style.visibility = visible ? "visible" : "hidden";
7542                 }
7543             }else{
7544                 // closure for composites
7545                 var dom = this.dom;
7546                 var visMode = this.visibilityMode;
7547                 if(visible){
7548                     this.setOpacity(.01);
7549                     this.setVisible(true);
7550                 }
7551                 this.anim({opacity: { to: (visible?1:0) }},
7552                       this.preanim(arguments, 1),
7553                       null, .35, 'easeIn', function(){
7554                          if(!visible){
7555                              if(visMode == El.DISPLAY){
7556                                  dom.style.display = "none";
7557                              }else{
7558                                  dom.style.visibility = "hidden";
7559                              }
7560                              Roo.get(dom).setOpacity(1);
7561                          }
7562                      });
7563             }
7564             return this;
7565         },
7566
7567         /**
7568          * Returns true if display is not "none"
7569          * @return {Boolean}
7570          */
7571         isDisplayed : function() {
7572             return this.getStyle("display") != "none";
7573         },
7574
7575         /**
7576          * Toggles the element's visibility or display, depending on visibility mode.
7577          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7578          * @return {Roo.Element} this
7579          */
7580         toggle : function(animate){
7581             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7582             return this;
7583         },
7584
7585         /**
7586          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7587          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7588          * @return {Roo.Element} this
7589          */
7590         setDisplayed : function(value) {
7591             if(typeof value == "boolean"){
7592                value = value ? this.originalDisplay : "none";
7593             }
7594             this.setStyle("display", value);
7595             return this;
7596         },
7597
7598         /**
7599          * Tries to focus the element. Any exceptions are caught and ignored.
7600          * @return {Roo.Element} this
7601          */
7602         focus : function() {
7603             try{
7604                 this.dom.focus();
7605             }catch(e){}
7606             return this;
7607         },
7608
7609         /**
7610          * Tries to blur the element. Any exceptions are caught and ignored.
7611          * @return {Roo.Element} this
7612          */
7613         blur : function() {
7614             try{
7615                 this.dom.blur();
7616             }catch(e){}
7617             return this;
7618         },
7619
7620         /**
7621          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7622          * @param {String/Array} className The CSS class to add, or an array of classes
7623          * @return {Roo.Element} this
7624          */
7625         addClass : function(className){
7626             if(className instanceof Array){
7627                 for(var i = 0, len = className.length; i < len; i++) {
7628                     this.addClass(className[i]);
7629                 }
7630             }else{
7631                 if(className && !this.hasClass(className)){
7632                     this.dom.className = this.dom.className + " " + className;
7633                 }
7634             }
7635             return this;
7636         },
7637
7638         /**
7639          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7640          * @param {String/Array} className The CSS class to add, or an array of classes
7641          * @return {Roo.Element} this
7642          */
7643         radioClass : function(className){
7644             var siblings = this.dom.parentNode.childNodes;
7645             for(var i = 0; i < siblings.length; i++) {
7646                 var s = siblings[i];
7647                 if(s.nodeType == 1){
7648                     Roo.get(s).removeClass(className);
7649                 }
7650             }
7651             this.addClass(className);
7652             return this;
7653         },
7654
7655         /**
7656          * Removes one or more CSS classes from the element.
7657          * @param {String/Array} className The CSS class to remove, or an array of classes
7658          * @return {Roo.Element} this
7659          */
7660         removeClass : function(className){
7661             if(!className || !this.dom.className){
7662                 return this;
7663             }
7664             if(className instanceof Array){
7665                 for(var i = 0, len = className.length; i < len; i++) {
7666                     this.removeClass(className[i]);
7667                 }
7668             }else{
7669                 if(this.hasClass(className)){
7670                     var re = this.classReCache[className];
7671                     if (!re) {
7672                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7673                        this.classReCache[className] = re;
7674                     }
7675                     this.dom.className =
7676                         this.dom.className.replace(re, " ");
7677                 }
7678             }
7679             return this;
7680         },
7681
7682         // private
7683         classReCache: {},
7684
7685         /**
7686          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7687          * @param {String} className The CSS class to toggle
7688          * @return {Roo.Element} this
7689          */
7690         toggleClass : function(className){
7691             if(this.hasClass(className)){
7692                 this.removeClass(className);
7693             }else{
7694                 this.addClass(className);
7695             }
7696             return this;
7697         },
7698
7699         /**
7700          * Checks if the specified CSS class exists on this element's DOM node.
7701          * @param {String} className The CSS class to check for
7702          * @return {Boolean} True if the class exists, else false
7703          */
7704         hasClass : function(className){
7705             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7706         },
7707
7708         /**
7709          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7710          * @param {String} oldClassName The CSS class to replace
7711          * @param {String} newClassName The replacement CSS class
7712          * @return {Roo.Element} this
7713          */
7714         replaceClass : function(oldClassName, newClassName){
7715             this.removeClass(oldClassName);
7716             this.addClass(newClassName);
7717             return this;
7718         },
7719
7720         /**
7721          * Returns an object with properties matching the styles requested.
7722          * For example, el.getStyles('color', 'font-size', 'width') might return
7723          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7724          * @param {String} style1 A style name
7725          * @param {String} style2 A style name
7726          * @param {String} etc.
7727          * @return {Object} The style object
7728          */
7729         getStyles : function(){
7730             var a = arguments, len = a.length, r = {};
7731             for(var i = 0; i < len; i++){
7732                 r[a[i]] = this.getStyle(a[i]);
7733             }
7734             return r;
7735         },
7736
7737         /**
7738          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7739          * @param {String} property The style property whose value is returned.
7740          * @return {String} The current value of the style property for this element.
7741          */
7742         getStyle : function(){
7743             return view && view.getComputedStyle ?
7744                 function(prop){
7745                     var el = this.dom, v, cs, camel;
7746                     if(prop == 'float'){
7747                         prop = "cssFloat";
7748                     }
7749                     if(el.style && (v = el.style[prop])){
7750                         return v;
7751                     }
7752                     if(cs = view.getComputedStyle(el, "")){
7753                         if(!(camel = propCache[prop])){
7754                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7755                         }
7756                         return cs[camel];
7757                     }
7758                     return null;
7759                 } :
7760                 function(prop){
7761                     var el = this.dom, v, cs, camel;
7762                     if(prop == 'opacity'){
7763                         if(typeof el.style.filter == 'string'){
7764                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7765                             if(m){
7766                                 var fv = parseFloat(m[1]);
7767                                 if(!isNaN(fv)){
7768                                     return fv ? fv / 100 : 0;
7769                                 }
7770                             }
7771                         }
7772                         return 1;
7773                     }else if(prop == 'float'){
7774                         prop = "styleFloat";
7775                     }
7776                     if(!(camel = propCache[prop])){
7777                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7778                     }
7779                     if(v = el.style[camel]){
7780                         return v;
7781                     }
7782                     if(cs = el.currentStyle){
7783                         return cs[camel];
7784                     }
7785                     return null;
7786                 };
7787         }(),
7788
7789         /**
7790          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7791          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7792          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7793          * @return {Roo.Element} this
7794          */
7795         setStyle : function(prop, value){
7796             if(typeof prop == "string"){
7797                 
7798                 if (prop == 'float') {
7799                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7800                     return this;
7801                 }
7802                 
7803                 var camel;
7804                 if(!(camel = propCache[prop])){
7805                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7806                 }
7807                 
7808                 if(camel == 'opacity') {
7809                     this.setOpacity(value);
7810                 }else{
7811                     this.dom.style[camel] = value;
7812                 }
7813             }else{
7814                 for(var style in prop){
7815                     if(typeof prop[style] != "function"){
7816                        this.setStyle(style, prop[style]);
7817                     }
7818                 }
7819             }
7820             return this;
7821         },
7822
7823         /**
7824          * More flexible version of {@link #setStyle} for setting style properties.
7825          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7826          * a function which returns such a specification.
7827          * @return {Roo.Element} this
7828          */
7829         applyStyles : function(style){
7830             Roo.DomHelper.applyStyles(this.dom, style);
7831             return this;
7832         },
7833
7834         /**
7835           * 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).
7836           * @return {Number} The X position of the element
7837           */
7838         getX : function(){
7839             return D.getX(this.dom);
7840         },
7841
7842         /**
7843           * 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).
7844           * @return {Number} The Y position of the element
7845           */
7846         getY : function(){
7847             return D.getY(this.dom);
7848         },
7849
7850         /**
7851           * 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).
7852           * @return {Array} The XY position of the element
7853           */
7854         getXY : function(){
7855             return D.getXY(this.dom);
7856         },
7857
7858         /**
7859          * 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).
7860          * @param {Number} The X position of the element
7861          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7862          * @return {Roo.Element} this
7863          */
7864         setX : function(x, animate){
7865             if(!animate || !A){
7866                 D.setX(this.dom, x);
7867             }else{
7868                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7869             }
7870             return this;
7871         },
7872
7873         /**
7874          * 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).
7875          * @param {Number} The Y position of the element
7876          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7877          * @return {Roo.Element} this
7878          */
7879         setY : function(y, animate){
7880             if(!animate || !A){
7881                 D.setY(this.dom, y);
7882             }else{
7883                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7884             }
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7890          * @param {String} left The left CSS property value
7891          * @return {Roo.Element} this
7892          */
7893         setLeft : function(left){
7894             this.setStyle("left", this.addUnits(left));
7895             return this;
7896         },
7897
7898         /**
7899          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7900          * @param {String} top The top CSS property value
7901          * @return {Roo.Element} this
7902          */
7903         setTop : function(top){
7904             this.setStyle("top", this.addUnits(top));
7905             return this;
7906         },
7907
7908         /**
7909          * Sets the element's CSS right style.
7910          * @param {String} right The right CSS property value
7911          * @return {Roo.Element} this
7912          */
7913         setRight : function(right){
7914             this.setStyle("right", this.addUnits(right));
7915             return this;
7916         },
7917
7918         /**
7919          * Sets the element's CSS bottom style.
7920          * @param {String} bottom The bottom CSS property value
7921          * @return {Roo.Element} this
7922          */
7923         setBottom : function(bottom){
7924             this.setStyle("bottom", this.addUnits(bottom));
7925             return this;
7926         },
7927
7928         /**
7929          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7930          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7931          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7932          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         setXY : function(pos, animate){
7936             if(!animate || !A){
7937                 D.setXY(this.dom, pos);
7938             }else{
7939                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7940             }
7941             return this;
7942         },
7943
7944         /**
7945          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7946          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7947          * @param {Number} x X value for new position (coordinates are page-based)
7948          * @param {Number} y Y value for new position (coordinates are page-based)
7949          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7950          * @return {Roo.Element} this
7951          */
7952         setLocation : function(x, y, animate){
7953             this.setXY([x, y], this.preanim(arguments, 2));
7954             return this;
7955         },
7956
7957         /**
7958          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7959          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7960          * @param {Number} x X value for new position (coordinates are page-based)
7961          * @param {Number} y Y value for new position (coordinates are page-based)
7962          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7963          * @return {Roo.Element} this
7964          */
7965         moveTo : function(x, y, animate){
7966             this.setXY([x, y], this.preanim(arguments, 2));
7967             return this;
7968         },
7969
7970         /**
7971          * Returns the region of the given element.
7972          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7973          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7974          */
7975         getRegion : function(){
7976             return D.getRegion(this.dom);
7977         },
7978
7979         /**
7980          * Returns the offset height of the element
7981          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7982          * @return {Number} The element's height
7983          */
7984         getHeight : function(contentHeight){
7985             var h = this.dom.offsetHeight || 0;
7986             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7987         },
7988
7989         /**
7990          * Returns the offset width of the element
7991          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7992          * @return {Number} The element's width
7993          */
7994         getWidth : function(contentWidth){
7995             var w = this.dom.offsetWidth || 0;
7996             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7997         },
7998
7999         /**
8000          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8001          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8002          * if a height has not been set using CSS.
8003          * @return {Number}
8004          */
8005         getComputedHeight : function(){
8006             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8007             if(!h){
8008                 h = parseInt(this.getStyle('height'), 10) || 0;
8009                 if(!this.isBorderBox()){
8010                     h += this.getFrameWidth('tb');
8011                 }
8012             }
8013             return h;
8014         },
8015
8016         /**
8017          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8018          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8019          * if a width has not been set using CSS.
8020          * @return {Number}
8021          */
8022         getComputedWidth : function(){
8023             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8024             if(!w){
8025                 w = parseInt(this.getStyle('width'), 10) || 0;
8026                 if(!this.isBorderBox()){
8027                     w += this.getFrameWidth('lr');
8028                 }
8029             }
8030             return w;
8031         },
8032
8033         /**
8034          * Returns the size of the element.
8035          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8036          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8037          */
8038         getSize : function(contentSize){
8039             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8040         },
8041
8042         /**
8043          * Returns the width and height of the viewport.
8044          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8045          */
8046         getViewSize : function(){
8047             var d = this.dom, doc = document, aw = 0, ah = 0;
8048             if(d == doc || d == doc.body){
8049                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8050             }else{
8051                 return {
8052                     width : d.clientWidth,
8053                     height: d.clientHeight
8054                 };
8055             }
8056         },
8057
8058         /**
8059          * Returns the value of the "value" attribute
8060          * @param {Boolean} asNumber true to parse the value as a number
8061          * @return {String/Number}
8062          */
8063         getValue : function(asNumber){
8064             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8065         },
8066
8067         // private
8068         adjustWidth : function(width){
8069             if(typeof width == "number"){
8070                 if(this.autoBoxAdjust && !this.isBorderBox()){
8071                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8072                 }
8073                 if(width < 0){
8074                     width = 0;
8075                 }
8076             }
8077             return width;
8078         },
8079
8080         // private
8081         adjustHeight : function(height){
8082             if(typeof height == "number"){
8083                if(this.autoBoxAdjust && !this.isBorderBox()){
8084                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8085                }
8086                if(height < 0){
8087                    height = 0;
8088                }
8089             }
8090             return height;
8091         },
8092
8093         /**
8094          * Set the width of the element
8095          * @param {Number} width The new width
8096          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8097          * @return {Roo.Element} this
8098          */
8099         setWidth : function(width, animate){
8100             width = this.adjustWidth(width);
8101             if(!animate || !A){
8102                 this.dom.style.width = this.addUnits(width);
8103             }else{
8104                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8105             }
8106             return this;
8107         },
8108
8109         /**
8110          * Set the height of the element
8111          * @param {Number} height The new height
8112          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8113          * @return {Roo.Element} this
8114          */
8115          setHeight : function(height, animate){
8116             height = this.adjustHeight(height);
8117             if(!animate || !A){
8118                 this.dom.style.height = this.addUnits(height);
8119             }else{
8120                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8121             }
8122             return this;
8123         },
8124
8125         /**
8126          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8127          * @param {Number} width The new width
8128          * @param {Number} height The new height
8129          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8130          * @return {Roo.Element} this
8131          */
8132          setSize : function(width, height, animate){
8133             if(typeof width == "object"){ // in case of object from getSize()
8134                 height = width.height; width = width.width;
8135             }
8136             width = this.adjustWidth(width); height = this.adjustHeight(height);
8137             if(!animate || !A){
8138                 this.dom.style.width = this.addUnits(width);
8139                 this.dom.style.height = this.addUnits(height);
8140             }else{
8141                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8142             }
8143             return this;
8144         },
8145
8146         /**
8147          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8148          * @param {Number} x X value for new position (coordinates are page-based)
8149          * @param {Number} y Y value for new position (coordinates are page-based)
8150          * @param {Number} width The new width
8151          * @param {Number} height The new height
8152          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8153          * @return {Roo.Element} this
8154          */
8155         setBounds : function(x, y, width, height, animate){
8156             if(!animate || !A){
8157                 this.setSize(width, height);
8158                 this.setLocation(x, y);
8159             }else{
8160                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8161                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8162                               this.preanim(arguments, 4), 'motion');
8163             }
8164             return this;
8165         },
8166
8167         /**
8168          * 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.
8169          * @param {Roo.lib.Region} region The region to fill
8170          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8171          * @return {Roo.Element} this
8172          */
8173         setRegion : function(region, animate){
8174             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8175             return this;
8176         },
8177
8178         /**
8179          * Appends an event handler
8180          *
8181          * @param {String}   eventName     The type of event to append
8182          * @param {Function} fn        The method the event invokes
8183          * @param {Object} scope       (optional) The scope (this object) of the fn
8184          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8185          */
8186         addListener : function(eventName, fn, scope, options){
8187             if (this.dom) {
8188                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8189             }
8190         },
8191
8192         /**
8193          * Removes an event handler from this element
8194          * @param {String} eventName the type of event to remove
8195          * @param {Function} fn the method the event invokes
8196          * @return {Roo.Element} this
8197          */
8198         removeListener : function(eventName, fn){
8199             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8200             return this;
8201         },
8202
8203         /**
8204          * Removes all previous added listeners from this element
8205          * @return {Roo.Element} this
8206          */
8207         removeAllListeners : function(){
8208             E.purgeElement(this.dom);
8209             return this;
8210         },
8211
8212         relayEvent : function(eventName, observable){
8213             this.on(eventName, function(e){
8214                 observable.fireEvent(eventName, e);
8215             });
8216         },
8217
8218         /**
8219          * Set the opacity of the element
8220          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8221          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8222          * @return {Roo.Element} this
8223          */
8224          setOpacity : function(opacity, animate){
8225             if(!animate || !A){
8226                 var s = this.dom.style;
8227                 if(Roo.isIE){
8228                     s.zoom = 1;
8229                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8230                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8231                 }else{
8232                     s.opacity = opacity;
8233                 }
8234             }else{
8235                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8236             }
8237             return this;
8238         },
8239
8240         /**
8241          * Gets the left X coordinate
8242          * @param {Boolean} local True to get the local css position instead of page coordinate
8243          * @return {Number}
8244          */
8245         getLeft : function(local){
8246             if(!local){
8247                 return this.getX();
8248             }else{
8249                 return parseInt(this.getStyle("left"), 10) || 0;
8250             }
8251         },
8252
8253         /**
8254          * Gets the right X coordinate of the element (element X position + element width)
8255          * @param {Boolean} local True to get the local css position instead of page coordinate
8256          * @return {Number}
8257          */
8258         getRight : function(local){
8259             if(!local){
8260                 return this.getX() + this.getWidth();
8261             }else{
8262                 return (this.getLeft(true) + this.getWidth()) || 0;
8263             }
8264         },
8265
8266         /**
8267          * Gets the top Y coordinate
8268          * @param {Boolean} local True to get the local css position instead of page coordinate
8269          * @return {Number}
8270          */
8271         getTop : function(local) {
8272             if(!local){
8273                 return this.getY();
8274             }else{
8275                 return parseInt(this.getStyle("top"), 10) || 0;
8276             }
8277         },
8278
8279         /**
8280          * Gets the bottom Y coordinate of the element (element Y position + element height)
8281          * @param {Boolean} local True to get the local css position instead of page coordinate
8282          * @return {Number}
8283          */
8284         getBottom : function(local){
8285             if(!local){
8286                 return this.getY() + this.getHeight();
8287             }else{
8288                 return (this.getTop(true) + this.getHeight()) || 0;
8289             }
8290         },
8291
8292         /**
8293         * Initializes positioning on this element. If a desired position is not passed, it will make the
8294         * the element positioned relative IF it is not already positioned.
8295         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8296         * @param {Number} zIndex (optional) The zIndex to apply
8297         * @param {Number} x (optional) Set the page X position
8298         * @param {Number} y (optional) Set the page Y position
8299         */
8300         position : function(pos, zIndex, x, y){
8301             if(!pos){
8302                if(this.getStyle('position') == 'static'){
8303                    this.setStyle('position', 'relative');
8304                }
8305             }else{
8306                 this.setStyle("position", pos);
8307             }
8308             if(zIndex){
8309                 this.setStyle("z-index", zIndex);
8310             }
8311             if(x !== undefined && y !== undefined){
8312                 this.setXY([x, y]);
8313             }else if(x !== undefined){
8314                 this.setX(x);
8315             }else if(y !== undefined){
8316                 this.setY(y);
8317             }
8318         },
8319
8320         /**
8321         * Clear positioning back to the default when the document was loaded
8322         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8323         * @return {Roo.Element} this
8324          */
8325         clearPositioning : function(value){
8326             value = value ||'';
8327             this.setStyle({
8328                 "left": value,
8329                 "right": value,
8330                 "top": value,
8331                 "bottom": value,
8332                 "z-index": "",
8333                 "position" : "static"
8334             });
8335             return this;
8336         },
8337
8338         /**
8339         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8340         * snapshot before performing an update and then restoring the element.
8341         * @return {Object}
8342         */
8343         getPositioning : function(){
8344             var l = this.getStyle("left");
8345             var t = this.getStyle("top");
8346             return {
8347                 "position" : this.getStyle("position"),
8348                 "left" : l,
8349                 "right" : l ? "" : this.getStyle("right"),
8350                 "top" : t,
8351                 "bottom" : t ? "" : this.getStyle("bottom"),
8352                 "z-index" : this.getStyle("z-index")
8353             };
8354         },
8355
8356         /**
8357          * Gets the width of the border(s) for the specified side(s)
8358          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8359          * passing lr would get the border (l)eft width + the border (r)ight width.
8360          * @return {Number} The width of the sides passed added together
8361          */
8362         getBorderWidth : function(side){
8363             return this.addStyles(side, El.borders);
8364         },
8365
8366         /**
8367          * Gets the width of the padding(s) for the specified side(s)
8368          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8369          * passing lr would get the padding (l)eft + the padding (r)ight.
8370          * @return {Number} The padding of the sides passed added together
8371          */
8372         getPadding : function(side){
8373             return this.addStyles(side, El.paddings);
8374         },
8375
8376         /**
8377         * Set positioning with an object returned by getPositioning().
8378         * @param {Object} posCfg
8379         * @return {Roo.Element} this
8380          */
8381         setPositioning : function(pc){
8382             this.applyStyles(pc);
8383             if(pc.right == "auto"){
8384                 this.dom.style.right = "";
8385             }
8386             if(pc.bottom == "auto"){
8387                 this.dom.style.bottom = "";
8388             }
8389             return this;
8390         },
8391
8392         // private
8393         fixDisplay : function(){
8394             if(this.getStyle("display") == "none"){
8395                 this.setStyle("visibility", "hidden");
8396                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8397                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8398                     this.setStyle("display", "block");
8399                 }
8400             }
8401         },
8402
8403         /**
8404          * Quick set left and top adding default units
8405          * @param {String} left The left CSS property value
8406          * @param {String} top The top CSS property value
8407          * @return {Roo.Element} this
8408          */
8409          setLeftTop : function(left, top){
8410             this.dom.style.left = this.addUnits(left);
8411             this.dom.style.top = this.addUnits(top);
8412             return this;
8413         },
8414
8415         /**
8416          * Move this element relative to its current position.
8417          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8418          * @param {Number} distance How far to move the element in pixels
8419          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8420          * @return {Roo.Element} this
8421          */
8422          move : function(direction, distance, animate){
8423             var xy = this.getXY();
8424             direction = direction.toLowerCase();
8425             switch(direction){
8426                 case "l":
8427                 case "left":
8428                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8429                     break;
8430                case "r":
8431                case "right":
8432                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8433                     break;
8434                case "t":
8435                case "top":
8436                case "up":
8437                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8438                     break;
8439                case "b":
8440                case "bottom":
8441                case "down":
8442                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8443                     break;
8444             }
8445             return this;
8446         },
8447
8448         /**
8449          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8450          * @return {Roo.Element} this
8451          */
8452         clip : function(){
8453             if(!this.isClipped){
8454                this.isClipped = true;
8455                this.originalClip = {
8456                    "o": this.getStyle("overflow"),
8457                    "x": this.getStyle("overflow-x"),
8458                    "y": this.getStyle("overflow-y")
8459                };
8460                this.setStyle("overflow", "hidden");
8461                this.setStyle("overflow-x", "hidden");
8462                this.setStyle("overflow-y", "hidden");
8463             }
8464             return this;
8465         },
8466
8467         /**
8468          *  Return clipping (overflow) to original clipping before clip() was called
8469          * @return {Roo.Element} this
8470          */
8471         unclip : function(){
8472             if(this.isClipped){
8473                 this.isClipped = false;
8474                 var o = this.originalClip;
8475                 if(o.o){this.setStyle("overflow", o.o);}
8476                 if(o.x){this.setStyle("overflow-x", o.x);}
8477                 if(o.y){this.setStyle("overflow-y", o.y);}
8478             }
8479             return this;
8480         },
8481
8482
8483         /**
8484          * Gets the x,y coordinates specified by the anchor position on the element.
8485          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8486          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8487          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8488          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8489          * @return {Array} [x, y] An array containing the element's x and y coordinates
8490          */
8491         getAnchorXY : function(anchor, local, s){
8492             //Passing a different size is useful for pre-calculating anchors,
8493             //especially for anchored animations that change the el size.
8494
8495             var w, h, vp = false;
8496             if(!s){
8497                 var d = this.dom;
8498                 if(d == document.body || d == document){
8499                     vp = true;
8500                     w = D.getViewWidth(); h = D.getViewHeight();
8501                 }else{
8502                     w = this.getWidth(); h = this.getHeight();
8503                 }
8504             }else{
8505                 w = s.width;  h = s.height;
8506             }
8507             var x = 0, y = 0, r = Math.round;
8508             switch((anchor || "tl").toLowerCase()){
8509                 case "c":
8510                     x = r(w*.5);
8511                     y = r(h*.5);
8512                 break;
8513                 case "t":
8514                     x = r(w*.5);
8515                     y = 0;
8516                 break;
8517                 case "l":
8518                     x = 0;
8519                     y = r(h*.5);
8520                 break;
8521                 case "r":
8522                     x = w;
8523                     y = r(h*.5);
8524                 break;
8525                 case "b":
8526                     x = r(w*.5);
8527                     y = h;
8528                 break;
8529                 case "tl":
8530                     x = 0;
8531                     y = 0;
8532                 break;
8533                 case "bl":
8534                     x = 0;
8535                     y = h;
8536                 break;
8537                 case "br":
8538                     x = w;
8539                     y = h;
8540                 break;
8541                 case "tr":
8542                     x = w;
8543                     y = 0;
8544                 break;
8545             }
8546             if(local === true){
8547                 return [x, y];
8548             }
8549             if(vp){
8550                 var sc = this.getScroll();
8551                 return [x + sc.left, y + sc.top];
8552             }
8553             //Add the element's offset xy
8554             var o = this.getXY();
8555             return [x+o[0], y+o[1]];
8556         },
8557
8558         /**
8559          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8560          * supported position values.
8561          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8562          * @param {String} position The position to align to.
8563          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8564          * @return {Array} [x, y]
8565          */
8566         getAlignToXY : function(el, p, o){
8567             el = Roo.get(el);
8568             var d = this.dom;
8569             if(!el.dom){
8570                 throw "Element.alignTo with an element that doesn't exist";
8571             }
8572             var c = false; //constrain to viewport
8573             var p1 = "", p2 = "";
8574             o = o || [0,0];
8575
8576             if(!p){
8577                 p = "tl-bl";
8578             }else if(p == "?"){
8579                 p = "tl-bl?";
8580             }else if(p.indexOf("-") == -1){
8581                 p = "tl-" + p;
8582             }
8583             p = p.toLowerCase();
8584             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8585             if(!m){
8586                throw "Element.alignTo with an invalid alignment " + p;
8587             }
8588             p1 = m[1]; p2 = m[2]; c = !!m[3];
8589
8590             //Subtract the aligned el's internal xy from the target's offset xy
8591             //plus custom offset to get the aligned el's new offset xy
8592             var a1 = this.getAnchorXY(p1, true);
8593             var a2 = el.getAnchorXY(p2, false);
8594             var x = a2[0] - a1[0] + o[0];
8595             var y = a2[1] - a1[1] + o[1];
8596             if(c){
8597                 //constrain the aligned el to viewport if necessary
8598                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8599                 // 5px of margin for ie
8600                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8601
8602                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8603                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8604                 //otherwise swap the aligned el to the opposite border of the target.
8605                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8606                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8607                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8608                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8609
8610                var doc = document;
8611                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8612                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8613
8614                if((x+w) > dw + scrollX){
8615                     x = swapX ? r.left-w : dw+scrollX-w;
8616                 }
8617                if(x < scrollX){
8618                    x = swapX ? r.right : scrollX;
8619                }
8620                if((y+h) > dh + scrollY){
8621                     y = swapY ? r.top-h : dh+scrollY-h;
8622                 }
8623                if (y < scrollY){
8624                    y = swapY ? r.bottom : scrollY;
8625                }
8626             }
8627             return [x,y];
8628         },
8629
8630         // private
8631         getConstrainToXY : function(){
8632             var os = {top:0, left:0, bottom:0, right: 0};
8633
8634             return function(el, local, offsets, proposedXY){
8635                 el = Roo.get(el);
8636                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8637
8638                 var vw, vh, vx = 0, vy = 0;
8639                 if(el.dom == document.body || el.dom == document){
8640                     vw = Roo.lib.Dom.getViewWidth();
8641                     vh = Roo.lib.Dom.getViewHeight();
8642                 }else{
8643                     vw = el.dom.clientWidth;
8644                     vh = el.dom.clientHeight;
8645                     if(!local){
8646                         var vxy = el.getXY();
8647                         vx = vxy[0];
8648                         vy = vxy[1];
8649                     }
8650                 }
8651
8652                 var s = el.getScroll();
8653
8654                 vx += offsets.left + s.left;
8655                 vy += offsets.top + s.top;
8656
8657                 vw -= offsets.right;
8658                 vh -= offsets.bottom;
8659
8660                 var vr = vx+vw;
8661                 var vb = vy+vh;
8662
8663                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8664                 var x = xy[0], y = xy[1];
8665                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8666
8667                 // only move it if it needs it
8668                 var moved = false;
8669
8670                 // first validate right/bottom
8671                 if((x + w) > vr){
8672                     x = vr - w;
8673                     moved = true;
8674                 }
8675                 if((y + h) > vb){
8676                     y = vb - h;
8677                     moved = true;
8678                 }
8679                 // then make sure top/left isn't negative
8680                 if(x < vx){
8681                     x = vx;
8682                     moved = true;
8683                 }
8684                 if(y < vy){
8685                     y = vy;
8686                     moved = true;
8687                 }
8688                 return moved ? [x, y] : false;
8689             };
8690         }(),
8691
8692         // private
8693         adjustForConstraints : function(xy, parent, offsets){
8694             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8695         },
8696
8697         /**
8698          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8699          * document it aligns it to the viewport.
8700          * The position parameter is optional, and can be specified in any one of the following formats:
8701          * <ul>
8702          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8703          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8704          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8705          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8706          *   <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
8707          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8708          * </ul>
8709          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8710          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8711          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8712          * that specified in order to enforce the viewport constraints.
8713          * Following are all of the supported anchor positions:
8714     <pre>
8715     Value  Description
8716     -----  -----------------------------
8717     tl     The top left corner (default)
8718     t      The center of the top edge
8719     tr     The top right corner
8720     l      The center of the left edge
8721     c      In the center of the element
8722     r      The center of the right edge
8723     bl     The bottom left corner
8724     b      The center of the bottom edge
8725     br     The bottom right corner
8726     </pre>
8727     Example Usage:
8728     <pre><code>
8729     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8730     el.alignTo("other-el");
8731
8732     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8733     el.alignTo("other-el", "tr?");
8734
8735     // align the bottom right corner of el with the center left edge of other-el
8736     el.alignTo("other-el", "br-l?");
8737
8738     // align the center of el with the bottom left corner of other-el and
8739     // adjust the x position by -6 pixels (and the y position by 0)
8740     el.alignTo("other-el", "c-bl", [-6, 0]);
8741     </code></pre>
8742          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8743          * @param {String} position The position to align to.
8744          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8745          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8746          * @return {Roo.Element} this
8747          */
8748         alignTo : function(element, position, offsets, animate){
8749             var xy = this.getAlignToXY(element, position, offsets);
8750             this.setXY(xy, this.preanim(arguments, 3));
8751             return this;
8752         },
8753
8754         /**
8755          * Anchors an element to another element and realigns it when the window is resized.
8756          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8757          * @param {String} position The position to align to.
8758          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8759          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8760          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8761          * is a number, it is used as the buffer delay (defaults to 50ms).
8762          * @param {Function} callback The function to call after the animation finishes
8763          * @return {Roo.Element} this
8764          */
8765         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8766             var action = function(){
8767                 this.alignTo(el, alignment, offsets, animate);
8768                 Roo.callback(callback, this);
8769             };
8770             Roo.EventManager.onWindowResize(action, this);
8771             var tm = typeof monitorScroll;
8772             if(tm != 'undefined'){
8773                 Roo.EventManager.on(window, 'scroll', action, this,
8774                     {buffer: tm == 'number' ? monitorScroll : 50});
8775             }
8776             action.call(this); // align immediately
8777             return this;
8778         },
8779         /**
8780          * Clears any opacity settings from this element. Required in some cases for IE.
8781          * @return {Roo.Element} this
8782          */
8783         clearOpacity : function(){
8784             if (window.ActiveXObject) {
8785                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8786                     this.dom.style.filter = "";
8787                 }
8788             } else {
8789                 this.dom.style.opacity = "";
8790                 this.dom.style["-moz-opacity"] = "";
8791                 this.dom.style["-khtml-opacity"] = "";
8792             }
8793             return this;
8794         },
8795
8796         /**
8797          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8798          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8799          * @return {Roo.Element} this
8800          */
8801         hide : function(animate){
8802             this.setVisible(false, this.preanim(arguments, 0));
8803             return this;
8804         },
8805
8806         /**
8807         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8808         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8809          * @return {Roo.Element} this
8810          */
8811         show : function(animate){
8812             this.setVisible(true, this.preanim(arguments, 0));
8813             return this;
8814         },
8815
8816         /**
8817          * @private Test if size has a unit, otherwise appends the default
8818          */
8819         addUnits : function(size){
8820             return Roo.Element.addUnits(size, this.defaultUnit);
8821         },
8822
8823         /**
8824          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8825          * @return {Roo.Element} this
8826          */
8827         beginMeasure : function(){
8828             var el = this.dom;
8829             if(el.offsetWidth || el.offsetHeight){
8830                 return this; // offsets work already
8831             }
8832             var changed = [];
8833             var p = this.dom, b = document.body; // start with this element
8834             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8835                 var pe = Roo.get(p);
8836                 if(pe.getStyle('display') == 'none'){
8837                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8838                     p.style.visibility = "hidden";
8839                     p.style.display = "block";
8840                 }
8841                 p = p.parentNode;
8842             }
8843             this._measureChanged = changed;
8844             return this;
8845
8846         },
8847
8848         /**
8849          * Restores displays to before beginMeasure was called
8850          * @return {Roo.Element} this
8851          */
8852         endMeasure : function(){
8853             var changed = this._measureChanged;
8854             if(changed){
8855                 for(var i = 0, len = changed.length; i < len; i++) {
8856                     var r = changed[i];
8857                     r.el.style.visibility = r.visibility;
8858                     r.el.style.display = "none";
8859                 }
8860                 this._measureChanged = null;
8861             }
8862             return this;
8863         },
8864
8865         /**
8866         * Update the innerHTML of this element, optionally searching for and processing scripts
8867         * @param {String} html The new HTML
8868         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8869         * @param {Function} callback For async script loading you can be noticed when the update completes
8870         * @return {Roo.Element} this
8871          */
8872         update : function(html, loadScripts, callback){
8873             if(typeof html == "undefined"){
8874                 html = "";
8875             }
8876             if(loadScripts !== true){
8877                 this.dom.innerHTML = html;
8878                 if(typeof callback == "function"){
8879                     callback();
8880                 }
8881                 return this;
8882             }
8883             var id = Roo.id();
8884             var dom = this.dom;
8885
8886             html += '<span id="' + id + '"></span>';
8887
8888             E.onAvailable(id, function(){
8889                 var hd = document.getElementsByTagName("head")[0];
8890                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8891                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8892                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8893
8894                 var match;
8895                 while(match = re.exec(html)){
8896                     var attrs = match[1];
8897                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8898                     if(srcMatch && srcMatch[2]){
8899                        var s = document.createElement("script");
8900                        s.src = srcMatch[2];
8901                        var typeMatch = attrs.match(typeRe);
8902                        if(typeMatch && typeMatch[2]){
8903                            s.type = typeMatch[2];
8904                        }
8905                        hd.appendChild(s);
8906                     }else if(match[2] && match[2].length > 0){
8907                         if(window.execScript) {
8908                            window.execScript(match[2]);
8909                         } else {
8910                             /**
8911                              * eval:var:id
8912                              * eval:var:dom
8913                              * eval:var:html
8914                              * 
8915                              */
8916                            window.eval(match[2]);
8917                         }
8918                     }
8919                 }
8920                 var el = document.getElementById(id);
8921                 if(el){el.parentNode.removeChild(el);}
8922                 if(typeof callback == "function"){
8923                     callback();
8924                 }
8925             });
8926             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8927             return this;
8928         },
8929
8930         /**
8931          * Direct access to the UpdateManager update() method (takes the same parameters).
8932          * @param {String/Function} url The url for this request or a function to call to get the url
8933          * @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}
8934          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8935          * @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.
8936          * @return {Roo.Element} this
8937          */
8938         load : function(){
8939             var um = this.getUpdateManager();
8940             um.update.apply(um, arguments);
8941             return this;
8942         },
8943
8944         /**
8945         * Gets this element's UpdateManager
8946         * @return {Roo.UpdateManager} The UpdateManager
8947         */
8948         getUpdateManager : function(){
8949             if(!this.updateManager){
8950                 this.updateManager = new Roo.UpdateManager(this);
8951             }
8952             return this.updateManager;
8953         },
8954
8955         /**
8956          * Disables text selection for this element (normalized across browsers)
8957          * @return {Roo.Element} this
8958          */
8959         unselectable : function(){
8960             this.dom.unselectable = "on";
8961             this.swallowEvent("selectstart", true);
8962             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8963             this.addClass("x-unselectable");
8964             return this;
8965         },
8966
8967         /**
8968         * Calculates the x, y to center this element on the screen
8969         * @return {Array} The x, y values [x, y]
8970         */
8971         getCenterXY : function(){
8972             return this.getAlignToXY(document, 'c-c');
8973         },
8974
8975         /**
8976         * Centers the Element in either the viewport, or another Element.
8977         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8978         */
8979         center : function(centerIn){
8980             this.alignTo(centerIn || document, 'c-c');
8981             return this;
8982         },
8983
8984         /**
8985          * Tests various css rules/browsers to determine if this element uses a border box
8986          * @return {Boolean}
8987          */
8988         isBorderBox : function(){
8989             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8990         },
8991
8992         /**
8993          * Return a box {x, y, width, height} that can be used to set another elements
8994          * size/location to match this element.
8995          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8996          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8997          * @return {Object} box An object in the format {x, y, width, height}
8998          */
8999         getBox : function(contentBox, local){
9000             var xy;
9001             if(!local){
9002                 xy = this.getXY();
9003             }else{
9004                 var left = parseInt(this.getStyle("left"), 10) || 0;
9005                 var top = parseInt(this.getStyle("top"), 10) || 0;
9006                 xy = [left, top];
9007             }
9008             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9009             if(!contentBox){
9010                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9011             }else{
9012                 var l = this.getBorderWidth("l")+this.getPadding("l");
9013                 var r = this.getBorderWidth("r")+this.getPadding("r");
9014                 var t = this.getBorderWidth("t")+this.getPadding("t");
9015                 var b = this.getBorderWidth("b")+this.getPadding("b");
9016                 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)};
9017             }
9018             bx.right = bx.x + bx.width;
9019             bx.bottom = bx.y + bx.height;
9020             return bx;
9021         },
9022
9023         /**
9024          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9025          for more information about the sides.
9026          * @param {String} sides
9027          * @return {Number}
9028          */
9029         getFrameWidth : function(sides, onlyContentBox){
9030             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9031         },
9032
9033         /**
9034          * 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.
9035          * @param {Object} box The box to fill {x, y, width, height}
9036          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9037          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9038          * @return {Roo.Element} this
9039          */
9040         setBox : function(box, adjust, animate){
9041             var w = box.width, h = box.height;
9042             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9043                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9044                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9045             }
9046             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9047             return this;
9048         },
9049
9050         /**
9051          * Forces the browser to repaint this element
9052          * @return {Roo.Element} this
9053          */
9054          repaint : function(){
9055             var dom = this.dom;
9056             this.addClass("x-repaint");
9057             setTimeout(function(){
9058                 Roo.get(dom).removeClass("x-repaint");
9059             }, 1);
9060             return this;
9061         },
9062
9063         /**
9064          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9065          * then it returns the calculated width of the sides (see getPadding)
9066          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9067          * @return {Object/Number}
9068          */
9069         getMargins : function(side){
9070             if(!side){
9071                 return {
9072                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9073                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9074                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9075                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9076                 };
9077             }else{
9078                 return this.addStyles(side, El.margins);
9079              }
9080         },
9081
9082         // private
9083         addStyles : function(sides, styles){
9084             var val = 0, v, w;
9085             for(var i = 0, len = sides.length; i < len; i++){
9086                 v = this.getStyle(styles[sides.charAt(i)]);
9087                 if(v){
9088                      w = parseInt(v, 10);
9089                      if(w){ val += w; }
9090                 }
9091             }
9092             return val;
9093         },
9094
9095         /**
9096          * Creates a proxy element of this element
9097          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9098          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9099          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9100          * @return {Roo.Element} The new proxy element
9101          */
9102         createProxy : function(config, renderTo, matchBox){
9103             if(renderTo){
9104                 renderTo = Roo.getDom(renderTo);
9105             }else{
9106                 renderTo = document.body;
9107             }
9108             config = typeof config == "object" ?
9109                 config : {tag : "div", cls: config};
9110             var proxy = Roo.DomHelper.append(renderTo, config, true);
9111             if(matchBox){
9112                proxy.setBox(this.getBox());
9113             }
9114             return proxy;
9115         },
9116
9117         /**
9118          * Puts a mask over this element to disable user interaction. Requires core.css.
9119          * This method can only be applied to elements which accept child nodes.
9120          * @param {String} msg (optional) A message to display in the mask
9121          * @param {String} msgCls (optional) A css class to apply to the msg element
9122          * @return {Element} The mask  element
9123          */
9124         mask : function(msg, msgCls)
9125         {
9126             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9127                 this.setStyle("position", "relative");
9128             }
9129             if(!this._mask){
9130                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9131             }
9132             this.addClass("x-masked");
9133             this._mask.setDisplayed(true);
9134             
9135             // we wander
9136             var z = 0;
9137             var dom = this.dom;
9138             while (dom && dom.style) {
9139                 if (!isNaN(parseInt(dom.style.zIndex))) {
9140                     z = Math.max(z, parseInt(dom.style.zIndex));
9141                 }
9142                 dom = dom.parentNode;
9143             }
9144             // if we are masking the body - then it hides everything..
9145             if (this.dom == document.body) {
9146                 z = 1000000;
9147                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9148                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9149             }
9150            
9151             if(typeof msg == 'string'){
9152                 if(!this._maskMsg){
9153                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9154                         cls: "roo-el-mask-msg", 
9155                         cn: [
9156                             {
9157                                 tag: 'i',
9158                                 cls: 'fa fa-spinner fa-spin'
9159                             },
9160                             {
9161                                 tag: 'div'
9162                             }   
9163                         ]
9164                     }, true);
9165                 }
9166                 var mm = this._maskMsg;
9167                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9168                 if (mm.dom.lastChild) { // weird IE issue?
9169                     mm.dom.lastChild.innerHTML = msg;
9170                 }
9171                 mm.setDisplayed(true);
9172                 mm.center(this);
9173                 mm.setStyle('z-index', z + 102);
9174             }
9175             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9176                 this._mask.setHeight(this.getHeight());
9177             }
9178             this._mask.setStyle('z-index', z + 100);
9179             
9180             return this._mask;
9181         },
9182
9183         /**
9184          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9185          * it is cached for reuse.
9186          */
9187         unmask : function(removeEl){
9188             if(this._mask){
9189                 if(removeEl === true){
9190                     this._mask.remove();
9191                     delete this._mask;
9192                     if(this._maskMsg){
9193                         this._maskMsg.remove();
9194                         delete this._maskMsg;
9195                     }
9196                 }else{
9197                     this._mask.setDisplayed(false);
9198                     if(this._maskMsg){
9199                         this._maskMsg.setDisplayed(false);
9200                     }
9201                 }
9202             }
9203             this.removeClass("x-masked");
9204         },
9205
9206         /**
9207          * Returns true if this element is masked
9208          * @return {Boolean}
9209          */
9210         isMasked : function(){
9211             return this._mask && this._mask.isVisible();
9212         },
9213
9214         /**
9215          * Creates an iframe shim for this element to keep selects and other windowed objects from
9216          * showing through.
9217          * @return {Roo.Element} The new shim element
9218          */
9219         createShim : function(){
9220             var el = document.createElement('iframe');
9221             el.frameBorder = 'no';
9222             el.className = 'roo-shim';
9223             if(Roo.isIE && Roo.isSecure){
9224                 el.src = Roo.SSL_SECURE_URL;
9225             }
9226             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9227             shim.autoBoxAdjust = false;
9228             return shim;
9229         },
9230
9231         /**
9232          * Removes this element from the DOM and deletes it from the cache
9233          */
9234         remove : function(){
9235             if(this.dom.parentNode){
9236                 this.dom.parentNode.removeChild(this.dom);
9237             }
9238             delete El.cache[this.dom.id];
9239         },
9240
9241         /**
9242          * Sets up event handlers to add and remove a css class when the mouse is over this element
9243          * @param {String} className
9244          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9245          * mouseout events for children elements
9246          * @return {Roo.Element} this
9247          */
9248         addClassOnOver : function(className, preventFlicker){
9249             this.on("mouseover", function(){
9250                 Roo.fly(this, '_internal').addClass(className);
9251             }, this.dom);
9252             var removeFn = function(e){
9253                 if(preventFlicker !== true || !e.within(this, true)){
9254                     Roo.fly(this, '_internal').removeClass(className);
9255                 }
9256             };
9257             this.on("mouseout", removeFn, this.dom);
9258             return this;
9259         },
9260
9261         /**
9262          * Sets up event handlers to add and remove a css class when this element has the focus
9263          * @param {String} className
9264          * @return {Roo.Element} this
9265          */
9266         addClassOnFocus : function(className){
9267             this.on("focus", function(){
9268                 Roo.fly(this, '_internal').addClass(className);
9269             }, this.dom);
9270             this.on("blur", function(){
9271                 Roo.fly(this, '_internal').removeClass(className);
9272             }, this.dom);
9273             return this;
9274         },
9275         /**
9276          * 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)
9277          * @param {String} className
9278          * @return {Roo.Element} this
9279          */
9280         addClassOnClick : function(className){
9281             var dom = this.dom;
9282             this.on("mousedown", function(){
9283                 Roo.fly(dom, '_internal').addClass(className);
9284                 var d = Roo.get(document);
9285                 var fn = function(){
9286                     Roo.fly(dom, '_internal').removeClass(className);
9287                     d.removeListener("mouseup", fn);
9288                 };
9289                 d.on("mouseup", fn);
9290             });
9291             return this;
9292         },
9293
9294         /**
9295          * Stops the specified event from bubbling and optionally prevents the default action
9296          * @param {String} eventName
9297          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9298          * @return {Roo.Element} this
9299          */
9300         swallowEvent : function(eventName, preventDefault){
9301             var fn = function(e){
9302                 e.stopPropagation();
9303                 if(preventDefault){
9304                     e.preventDefault();
9305                 }
9306             };
9307             if(eventName instanceof Array){
9308                 for(var i = 0, len = eventName.length; i < len; i++){
9309                      this.on(eventName[i], fn);
9310                 }
9311                 return this;
9312             }
9313             this.on(eventName, fn);
9314             return this;
9315         },
9316
9317         /**
9318          * @private
9319          */
9320       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9321
9322         /**
9323          * Sizes this element to its parent element's dimensions performing
9324          * neccessary box adjustments.
9325          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9326          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9327          * @return {Roo.Element} this
9328          */
9329         fitToParent : function(monitorResize, targetParent) {
9330           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9331           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9332           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9333             return;
9334           }
9335           var p = Roo.get(targetParent || this.dom.parentNode);
9336           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9337           if (monitorResize === true) {
9338             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9339             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9340           }
9341           return this;
9342         },
9343
9344         /**
9345          * Gets the next sibling, skipping text nodes
9346          * @return {HTMLElement} The next sibling or null
9347          */
9348         getNextSibling : function(){
9349             var n = this.dom.nextSibling;
9350             while(n && n.nodeType != 1){
9351                 n = n.nextSibling;
9352             }
9353             return n;
9354         },
9355
9356         /**
9357          * Gets the previous sibling, skipping text nodes
9358          * @return {HTMLElement} The previous sibling or null
9359          */
9360         getPrevSibling : function(){
9361             var n = this.dom.previousSibling;
9362             while(n && n.nodeType != 1){
9363                 n = n.previousSibling;
9364             }
9365             return n;
9366         },
9367
9368
9369         /**
9370          * Appends the passed element(s) to this element
9371          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9372          * @return {Roo.Element} this
9373          */
9374         appendChild: function(el){
9375             el = Roo.get(el);
9376             el.appendTo(this);
9377             return this;
9378         },
9379
9380         /**
9381          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9382          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9383          * automatically generated with the specified attributes.
9384          * @param {HTMLElement} insertBefore (optional) a child element of this element
9385          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9386          * @return {Roo.Element} The new child element
9387          */
9388         createChild: function(config, insertBefore, returnDom){
9389             config = config || {tag:'div'};
9390             if(insertBefore){
9391                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9392             }
9393             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9394         },
9395
9396         /**
9397          * Appends this element to the passed element
9398          * @param {String/HTMLElement/Element} el The new parent element
9399          * @return {Roo.Element} this
9400          */
9401         appendTo: function(el){
9402             el = Roo.getDom(el);
9403             el.appendChild(this.dom);
9404             return this;
9405         },
9406
9407         /**
9408          * Inserts this element before the passed element in the DOM
9409          * @param {String/HTMLElement/Element} el The element to insert before
9410          * @return {Roo.Element} this
9411          */
9412         insertBefore: function(el){
9413             el = Roo.getDom(el);
9414             el.parentNode.insertBefore(this.dom, el);
9415             return this;
9416         },
9417
9418         /**
9419          * Inserts this element after the passed element in the DOM
9420          * @param {String/HTMLElement/Element} el The element to insert after
9421          * @return {Roo.Element} this
9422          */
9423         insertAfter: function(el){
9424             el = Roo.getDom(el);
9425             el.parentNode.insertBefore(this.dom, el.nextSibling);
9426             return this;
9427         },
9428
9429         /**
9430          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9431          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9432          * @return {Roo.Element} The new child
9433          */
9434         insertFirst: function(el, returnDom){
9435             el = el || {};
9436             if(typeof el == 'object' && !el.nodeType){ // dh config
9437                 return this.createChild(el, this.dom.firstChild, returnDom);
9438             }else{
9439                 el = Roo.getDom(el);
9440                 this.dom.insertBefore(el, this.dom.firstChild);
9441                 return !returnDom ? Roo.get(el) : el;
9442             }
9443         },
9444
9445         /**
9446          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9447          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9448          * @param {String} where (optional) 'before' or 'after' defaults to before
9449          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9450          * @return {Roo.Element} the inserted Element
9451          */
9452         insertSibling: function(el, where, returnDom){
9453             where = where ? where.toLowerCase() : 'before';
9454             el = el || {};
9455             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9456
9457             if(typeof el == 'object' && !el.nodeType){ // dh config
9458                 if(where == 'after' && !this.dom.nextSibling){
9459                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9460                 }else{
9461                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9462                 }
9463
9464             }else{
9465                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9466                             where == 'before' ? this.dom : this.dom.nextSibling);
9467                 if(!returnDom){
9468                     rt = Roo.get(rt);
9469                 }
9470             }
9471             return rt;
9472         },
9473
9474         /**
9475          * Creates and wraps this element with another element
9476          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9477          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9478          * @return {HTMLElement/Element} The newly created wrapper element
9479          */
9480         wrap: function(config, returnDom){
9481             if(!config){
9482                 config = {tag: "div"};
9483             }
9484             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9485             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9486             return newEl;
9487         },
9488
9489         /**
9490          * Replaces the passed element with this element
9491          * @param {String/HTMLElement/Element} el The element to replace
9492          * @return {Roo.Element} this
9493          */
9494         replace: function(el){
9495             el = Roo.get(el);
9496             this.insertBefore(el);
9497             el.remove();
9498             return this;
9499         },
9500
9501         /**
9502          * Inserts an html fragment into this element
9503          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9504          * @param {String} html The HTML fragment
9505          * @param {Boolean} returnEl True to return an Roo.Element
9506          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9507          */
9508         insertHtml : function(where, html, returnEl){
9509             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9510             return returnEl ? Roo.get(el) : el;
9511         },
9512
9513         /**
9514          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9515          * @param {Object} o The object with the attributes
9516          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9517          * @return {Roo.Element} this
9518          */
9519         set : function(o, useSet){
9520             var el = this.dom;
9521             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9522             for(var attr in o){
9523                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9524                 if(attr=="cls"){
9525                     el.className = o["cls"];
9526                 }else{
9527                     if(useSet) {
9528                         el.setAttribute(attr, o[attr]);
9529                     } else {
9530                         el[attr] = o[attr];
9531                     }
9532                 }
9533             }
9534             if(o.style){
9535                 Roo.DomHelper.applyStyles(el, o.style);
9536             }
9537             return this;
9538         },
9539
9540         /**
9541          * Convenience method for constructing a KeyMap
9542          * @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:
9543          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9544          * @param {Function} fn The function to call
9545          * @param {Object} scope (optional) The scope of the function
9546          * @return {Roo.KeyMap} The KeyMap created
9547          */
9548         addKeyListener : function(key, fn, scope){
9549             var config;
9550             if(typeof key != "object" || key instanceof Array){
9551                 config = {
9552                     key: key,
9553                     fn: fn,
9554                     scope: scope
9555                 };
9556             }else{
9557                 config = {
9558                     key : key.key,
9559                     shift : key.shift,
9560                     ctrl : key.ctrl,
9561                     alt : key.alt,
9562                     fn: fn,
9563                     scope: scope
9564                 };
9565             }
9566             return new Roo.KeyMap(this, config);
9567         },
9568
9569         /**
9570          * Creates a KeyMap for this element
9571          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9572          * @return {Roo.KeyMap} The KeyMap created
9573          */
9574         addKeyMap : function(config){
9575             return new Roo.KeyMap(this, config);
9576         },
9577
9578         /**
9579          * Returns true if this element is scrollable.
9580          * @return {Boolean}
9581          */
9582          isScrollable : function(){
9583             var dom = this.dom;
9584             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9585         },
9586
9587         /**
9588          * 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().
9589          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9590          * @param {Number} value The new scroll value
9591          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9592          * @return {Element} this
9593          */
9594
9595         scrollTo : function(side, value, animate){
9596             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9597             if(!animate || !A){
9598                 this.dom[prop] = value;
9599             }else{
9600                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9601                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9602             }
9603             return this;
9604         },
9605
9606         /**
9607          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9608          * within this element's scrollable range.
9609          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9610          * @param {Number} distance How far to scroll the element in pixels
9611          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9612          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9613          * was scrolled as far as it could go.
9614          */
9615          scroll : function(direction, distance, animate){
9616              if(!this.isScrollable()){
9617                  return;
9618              }
9619              var el = this.dom;
9620              var l = el.scrollLeft, t = el.scrollTop;
9621              var w = el.scrollWidth, h = el.scrollHeight;
9622              var cw = el.clientWidth, ch = el.clientHeight;
9623              direction = direction.toLowerCase();
9624              var scrolled = false;
9625              var a = this.preanim(arguments, 2);
9626              switch(direction){
9627                  case "l":
9628                  case "left":
9629                      if(w - l > cw){
9630                          var v = Math.min(l + distance, w-cw);
9631                          this.scrollTo("left", v, a);
9632                          scrolled = true;
9633                      }
9634                      break;
9635                 case "r":
9636                 case "right":
9637                      if(l > 0){
9638                          var v = Math.max(l - distance, 0);
9639                          this.scrollTo("left", v, a);
9640                          scrolled = true;
9641                      }
9642                      break;
9643                 case "t":
9644                 case "top":
9645                 case "up":
9646                      if(t > 0){
9647                          var v = Math.max(t - distance, 0);
9648                          this.scrollTo("top", v, a);
9649                          scrolled = true;
9650                      }
9651                      break;
9652                 case "b":
9653                 case "bottom":
9654                 case "down":
9655                      if(h - t > ch){
9656                          var v = Math.min(t + distance, h-ch);
9657                          this.scrollTo("top", v, a);
9658                          scrolled = true;
9659                      }
9660                      break;
9661              }
9662              return scrolled;
9663         },
9664
9665         /**
9666          * Translates the passed page coordinates into left/top css values for this element
9667          * @param {Number/Array} x The page x or an array containing [x, y]
9668          * @param {Number} y The page y
9669          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9670          */
9671         translatePoints : function(x, y){
9672             if(typeof x == 'object' || x instanceof Array){
9673                 y = x[1]; x = x[0];
9674             }
9675             var p = this.getStyle('position');
9676             var o = this.getXY();
9677
9678             var l = parseInt(this.getStyle('left'), 10);
9679             var t = parseInt(this.getStyle('top'), 10);
9680
9681             if(isNaN(l)){
9682                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9683             }
9684             if(isNaN(t)){
9685                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9686             }
9687
9688             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9689         },
9690
9691         /**
9692          * Returns the current scroll position of the element.
9693          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9694          */
9695         getScroll : function(){
9696             var d = this.dom, doc = document;
9697             if(d == doc || d == doc.body){
9698                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9699                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9700                 return {left: l, top: t};
9701             }else{
9702                 return {left: d.scrollLeft, top: d.scrollTop};
9703             }
9704         },
9705
9706         /**
9707          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9708          * are convert to standard 6 digit hex color.
9709          * @param {String} attr The css attribute
9710          * @param {String} defaultValue The default value to use when a valid color isn't found
9711          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9712          * YUI color anims.
9713          */
9714         getColor : function(attr, defaultValue, prefix){
9715             var v = this.getStyle(attr);
9716             if(!v || v == "transparent" || v == "inherit") {
9717                 return defaultValue;
9718             }
9719             var color = typeof prefix == "undefined" ? "#" : prefix;
9720             if(v.substr(0, 4) == "rgb("){
9721                 var rvs = v.slice(4, v.length -1).split(",");
9722                 for(var i = 0; i < 3; i++){
9723                     var h = parseInt(rvs[i]).toString(16);
9724                     if(h < 16){
9725                         h = "0" + h;
9726                     }
9727                     color += h;
9728                 }
9729             } else {
9730                 if(v.substr(0, 1) == "#"){
9731                     if(v.length == 4) {
9732                         for(var i = 1; i < 4; i++){
9733                             var c = v.charAt(i);
9734                             color +=  c + c;
9735                         }
9736                     }else if(v.length == 7){
9737                         color += v.substr(1);
9738                     }
9739                 }
9740             }
9741             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9742         },
9743
9744         /**
9745          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9746          * gradient background, rounded corners and a 4-way shadow.
9747          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9748          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9749          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9750          * @return {Roo.Element} this
9751          */
9752         boxWrap : function(cls){
9753             cls = cls || 'x-box';
9754             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9755             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9756             return el;
9757         },
9758
9759         /**
9760          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9761          * @param {String} namespace The namespace in which to look for the attribute
9762          * @param {String} name The attribute name
9763          * @return {String} The attribute value
9764          */
9765         getAttributeNS : Roo.isIE ? function(ns, name){
9766             var d = this.dom;
9767             var type = typeof d[ns+":"+name];
9768             if(type != 'undefined' && type != 'unknown'){
9769                 return d[ns+":"+name];
9770             }
9771             return d[name];
9772         } : function(ns, name){
9773             var d = this.dom;
9774             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9775         },
9776         
9777         
9778         /**
9779          * Sets or Returns the value the dom attribute value
9780          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9781          * @param {String} value (optional) The value to set the attribute to
9782          * @return {String} The attribute value
9783          */
9784         attr : function(name){
9785             if (arguments.length > 1) {
9786                 this.dom.setAttribute(name, arguments[1]);
9787                 return arguments[1];
9788             }
9789             if (typeof(name) == 'object') {
9790                 for(var i in name) {
9791                     this.attr(i, name[i]);
9792                 }
9793                 return name;
9794             }
9795             
9796             
9797             if (!this.dom.hasAttribute(name)) {
9798                 return undefined;
9799             }
9800             return this.dom.getAttribute(name);
9801         }
9802         
9803         
9804         
9805     };
9806
9807     var ep = El.prototype;
9808
9809     /**
9810      * Appends an event handler (Shorthand for addListener)
9811      * @param {String}   eventName     The type of event to append
9812      * @param {Function} fn        The method the event invokes
9813      * @param {Object} scope       (optional) The scope (this object) of the fn
9814      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9815      * @method
9816      */
9817     ep.on = ep.addListener;
9818         // backwards compat
9819     ep.mon = ep.addListener;
9820
9821     /**
9822      * Removes an event handler from this element (shorthand for removeListener)
9823      * @param {String} eventName the type of event to remove
9824      * @param {Function} fn the method the event invokes
9825      * @return {Roo.Element} this
9826      * @method
9827      */
9828     ep.un = ep.removeListener;
9829
9830     /**
9831      * true to automatically adjust width and height settings for box-model issues (default to true)
9832      */
9833     ep.autoBoxAdjust = true;
9834
9835     // private
9836     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9837
9838     // private
9839     El.addUnits = function(v, defaultUnit){
9840         if(v === "" || v == "auto"){
9841             return v;
9842         }
9843         if(v === undefined){
9844             return '';
9845         }
9846         if(typeof v == "number" || !El.unitPattern.test(v)){
9847             return v + (defaultUnit || 'px');
9848         }
9849         return v;
9850     };
9851
9852     // special markup used throughout Roo when box wrapping elements
9853     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>';
9854     /**
9855      * Visibility mode constant - Use visibility to hide element
9856      * @static
9857      * @type Number
9858      */
9859     El.VISIBILITY = 1;
9860     /**
9861      * Visibility mode constant - Use display to hide element
9862      * @static
9863      * @type Number
9864      */
9865     El.DISPLAY = 2;
9866
9867     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9868     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9869     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9870
9871
9872
9873     /**
9874      * @private
9875      */
9876     El.cache = {};
9877
9878     var docEl;
9879
9880     /**
9881      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9882      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9883      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9884      * @return {Element} The Element object
9885      * @static
9886      */
9887     El.get = function(el){
9888         var ex, elm, id;
9889         if(!el){ return null; }
9890         if(typeof el == "string"){ // element id
9891             if(!(elm = document.getElementById(el))){
9892                 return null;
9893             }
9894             if(ex = El.cache[el]){
9895                 ex.dom = elm;
9896             }else{
9897                 ex = El.cache[el] = new El(elm);
9898             }
9899             return ex;
9900         }else if(el.tagName){ // dom element
9901             if(!(id = el.id)){
9902                 id = Roo.id(el);
9903             }
9904             if(ex = El.cache[id]){
9905                 ex.dom = el;
9906             }else{
9907                 ex = El.cache[id] = new El(el);
9908             }
9909             return ex;
9910         }else if(el instanceof El){
9911             if(el != docEl){
9912                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9913                                                               // catch case where it hasn't been appended
9914                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9915             }
9916             return el;
9917         }else if(el.isComposite){
9918             return el;
9919         }else if(el instanceof Array){
9920             return El.select(el);
9921         }else if(el == document){
9922             // create a bogus element object representing the document object
9923             if(!docEl){
9924                 var f = function(){};
9925                 f.prototype = El.prototype;
9926                 docEl = new f();
9927                 docEl.dom = document;
9928             }
9929             return docEl;
9930         }
9931         return null;
9932     };
9933
9934     // private
9935     El.uncache = function(el){
9936         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9937             if(a[i]){
9938                 delete El.cache[a[i].id || a[i]];
9939             }
9940         }
9941     };
9942
9943     // private
9944     // Garbage collection - uncache elements/purge listeners on orphaned elements
9945     // so we don't hold a reference and cause the browser to retain them
9946     El.garbageCollect = function(){
9947         if(!Roo.enableGarbageCollector){
9948             clearInterval(El.collectorThread);
9949             return;
9950         }
9951         for(var eid in El.cache){
9952             var el = El.cache[eid], d = el.dom;
9953             // -------------------------------------------------------
9954             // Determining what is garbage:
9955             // -------------------------------------------------------
9956             // !d
9957             // dom node is null, definitely garbage
9958             // -------------------------------------------------------
9959             // !d.parentNode
9960             // no parentNode == direct orphan, definitely garbage
9961             // -------------------------------------------------------
9962             // !d.offsetParent && !document.getElementById(eid)
9963             // display none elements have no offsetParent so we will
9964             // also try to look it up by it's id. However, check
9965             // offsetParent first so we don't do unneeded lookups.
9966             // This enables collection of elements that are not orphans
9967             // directly, but somewhere up the line they have an orphan
9968             // parent.
9969             // -------------------------------------------------------
9970             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9971                 delete El.cache[eid];
9972                 if(d && Roo.enableListenerCollection){
9973                     E.purgeElement(d);
9974                 }
9975             }
9976         }
9977     }
9978     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9979
9980
9981     // dom is optional
9982     El.Flyweight = function(dom){
9983         this.dom = dom;
9984     };
9985     El.Flyweight.prototype = El.prototype;
9986
9987     El._flyweights = {};
9988     /**
9989      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9990      * the dom node can be overwritten by other code.
9991      * @param {String/HTMLElement} el The dom node or id
9992      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9993      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9994      * @static
9995      * @return {Element} The shared Element object
9996      */
9997     El.fly = function(el, named){
9998         named = named || '_global';
9999         el = Roo.getDom(el);
10000         if(!el){
10001             return null;
10002         }
10003         if(!El._flyweights[named]){
10004             El._flyweights[named] = new El.Flyweight();
10005         }
10006         El._flyweights[named].dom = el;
10007         return El._flyweights[named];
10008     };
10009
10010     /**
10011      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10012      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10013      * Shorthand of {@link Roo.Element#get}
10014      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10015      * @return {Element} The Element object
10016      * @member Roo
10017      * @method get
10018      */
10019     Roo.get = El.get;
10020     /**
10021      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10022      * the dom node can be overwritten by other code.
10023      * Shorthand of {@link Roo.Element#fly}
10024      * @param {String/HTMLElement} el The dom node or id
10025      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10026      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10027      * @static
10028      * @return {Element} The shared Element object
10029      * @member Roo
10030      * @method fly
10031      */
10032     Roo.fly = El.fly;
10033
10034     // speedy lookup for elements never to box adjust
10035     var noBoxAdjust = Roo.isStrict ? {
10036         select:1
10037     } : {
10038         input:1, select:1, textarea:1
10039     };
10040     if(Roo.isIE || Roo.isGecko){
10041         noBoxAdjust['button'] = 1;
10042     }
10043
10044
10045     Roo.EventManager.on(window, 'unload', function(){
10046         delete El.cache;
10047         delete El._flyweights;
10048     });
10049 })();
10050
10051
10052
10053
10054 if(Roo.DomQuery){
10055     Roo.Element.selectorFunction = Roo.DomQuery.select;
10056 }
10057
10058 Roo.Element.select = function(selector, unique, root){
10059     var els;
10060     if(typeof selector == "string"){
10061         els = Roo.Element.selectorFunction(selector, root);
10062     }else if(selector.length !== undefined){
10063         els = selector;
10064     }else{
10065         throw "Invalid selector";
10066     }
10067     if(unique === true){
10068         return new Roo.CompositeElement(els);
10069     }else{
10070         return new Roo.CompositeElementLite(els);
10071     }
10072 };
10073 /**
10074  * Selects elements based on the passed CSS selector to enable working on them as 1.
10075  * @param {String/Array} selector The CSS selector or an array of elements
10076  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10077  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10078  * @return {CompositeElementLite/CompositeElement}
10079  * @member Roo
10080  * @method select
10081  */
10082 Roo.select = Roo.Element.select;
10083
10084
10085
10086
10087
10088
10089
10090
10091
10092
10093
10094
10095
10096
10097 /*
10098  * Based on:
10099  * Ext JS Library 1.1.1
10100  * Copyright(c) 2006-2007, Ext JS, LLC.
10101  *
10102  * Originally Released Under LGPL - original licence link has changed is not relivant.
10103  *
10104  * Fork - LGPL
10105  * <script type="text/javascript">
10106  */
10107
10108
10109
10110 //Notifies Element that fx methods are available
10111 Roo.enableFx = true;
10112
10113 /**
10114  * @class Roo.Fx
10115  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10116  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10117  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10118  * Element effects to work.</p><br/>
10119  *
10120  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10121  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10122  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10123  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10124  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10125  * expected results and should be done with care.</p><br/>
10126  *
10127  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10128  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10129 <pre>
10130 Value  Description
10131 -----  -----------------------------
10132 tl     The top left corner
10133 t      The center of the top edge
10134 tr     The top right corner
10135 l      The center of the left edge
10136 r      The center of the right edge
10137 bl     The bottom left corner
10138 b      The center of the bottom edge
10139 br     The bottom right corner
10140 </pre>
10141  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10142  * below are common options that can be passed to any Fx method.</b>
10143  * @cfg {Function} callback A function called when the effect is finished
10144  * @cfg {Object} scope The scope of the effect function
10145  * @cfg {String} easing A valid Easing value for the effect
10146  * @cfg {String} afterCls A css class to apply after the effect
10147  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10148  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10149  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10150  * effects that end with the element being visually hidden, ignored otherwise)
10151  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10152  * a function which returns such a specification that will be applied to the Element after the effect finishes
10153  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10154  * @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
10155  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10156  */
10157 Roo.Fx = {
10158         /**
10159          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10160          * origin for the slide effect.  This function automatically handles wrapping the element with
10161          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10162          * Usage:
10163          *<pre><code>
10164 // default: slide the element in from the top
10165 el.slideIn();
10166
10167 // custom: slide the element in from the right with a 2-second duration
10168 el.slideIn('r', { duration: 2 });
10169
10170 // common config options shown with default values
10171 el.slideIn('t', {
10172     easing: 'easeOut',
10173     duration: .5
10174 });
10175 </code></pre>
10176          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10177          * @param {Object} options (optional) Object literal with any of the Fx config options
10178          * @return {Roo.Element} The Element
10179          */
10180     slideIn : function(anchor, o){
10181         var el = this.getFxEl();
10182         o = o || {};
10183
10184         el.queueFx(o, function(){
10185
10186             anchor = anchor || "t";
10187
10188             // fix display to visibility
10189             this.fixDisplay();
10190
10191             // restore values after effect
10192             var r = this.getFxRestore();
10193             var b = this.getBox();
10194             // fixed size for slide
10195             this.setSize(b);
10196
10197             // wrap if needed
10198             var wrap = this.fxWrap(r.pos, o, "hidden");
10199
10200             var st = this.dom.style;
10201             st.visibility = "visible";
10202             st.position = "absolute";
10203
10204             // clear out temp styles after slide and unwrap
10205             var after = function(){
10206                 el.fxUnwrap(wrap, r.pos, o);
10207                 st.width = r.width;
10208                 st.height = r.height;
10209                 el.afterFx(o);
10210             };
10211             // time to calc the positions
10212             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10213
10214             switch(anchor.toLowerCase()){
10215                 case "t":
10216                     wrap.setSize(b.width, 0);
10217                     st.left = st.bottom = "0";
10218                     a = {height: bh};
10219                 break;
10220                 case "l":
10221                     wrap.setSize(0, b.height);
10222                     st.right = st.top = "0";
10223                     a = {width: bw};
10224                 break;
10225                 case "r":
10226                     wrap.setSize(0, b.height);
10227                     wrap.setX(b.right);
10228                     st.left = st.top = "0";
10229                     a = {width: bw, points: pt};
10230                 break;
10231                 case "b":
10232                     wrap.setSize(b.width, 0);
10233                     wrap.setY(b.bottom);
10234                     st.left = st.top = "0";
10235                     a = {height: bh, points: pt};
10236                 break;
10237                 case "tl":
10238                     wrap.setSize(0, 0);
10239                     st.right = st.bottom = "0";
10240                     a = {width: bw, height: bh};
10241                 break;
10242                 case "bl":
10243                     wrap.setSize(0, 0);
10244                     wrap.setY(b.y+b.height);
10245                     st.right = st.top = "0";
10246                     a = {width: bw, height: bh, points: pt};
10247                 break;
10248                 case "br":
10249                     wrap.setSize(0, 0);
10250                     wrap.setXY([b.right, b.bottom]);
10251                     st.left = st.top = "0";
10252                     a = {width: bw, height: bh, points: pt};
10253                 break;
10254                 case "tr":
10255                     wrap.setSize(0, 0);
10256                     wrap.setX(b.x+b.width);
10257                     st.left = st.bottom = "0";
10258                     a = {width: bw, height: bh, points: pt};
10259                 break;
10260             }
10261             this.dom.style.visibility = "visible";
10262             wrap.show();
10263
10264             arguments.callee.anim = wrap.fxanim(a,
10265                 o,
10266                 'motion',
10267                 .5,
10268                 'easeOut', after);
10269         });
10270         return this;
10271     },
10272     
10273         /**
10274          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10275          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10276          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10277          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10278          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10279          * Usage:
10280          *<pre><code>
10281 // default: slide the element out to the top
10282 el.slideOut();
10283
10284 // custom: slide the element out to the right with a 2-second duration
10285 el.slideOut('r', { duration: 2 });
10286
10287 // common config options shown with default values
10288 el.slideOut('t', {
10289     easing: 'easeOut',
10290     duration: .5,
10291     remove: false,
10292     useDisplay: false
10293 });
10294 </code></pre>
10295          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10296          * @param {Object} options (optional) Object literal with any of the Fx config options
10297          * @return {Roo.Element} The Element
10298          */
10299     slideOut : function(anchor, o){
10300         var el = this.getFxEl();
10301         o = o || {};
10302
10303         el.queueFx(o, function(){
10304
10305             anchor = anchor || "t";
10306
10307             // restore values after effect
10308             var r = this.getFxRestore();
10309             
10310             var b = this.getBox();
10311             // fixed size for slide
10312             this.setSize(b);
10313
10314             // wrap if needed
10315             var wrap = this.fxWrap(r.pos, o, "visible");
10316
10317             var st = this.dom.style;
10318             st.visibility = "visible";
10319             st.position = "absolute";
10320
10321             wrap.setSize(b);
10322
10323             var after = function(){
10324                 if(o.useDisplay){
10325                     el.setDisplayed(false);
10326                 }else{
10327                     el.hide();
10328                 }
10329
10330                 el.fxUnwrap(wrap, r.pos, o);
10331
10332                 st.width = r.width;
10333                 st.height = r.height;
10334
10335                 el.afterFx(o);
10336             };
10337
10338             var a, zero = {to: 0};
10339             switch(anchor.toLowerCase()){
10340                 case "t":
10341                     st.left = st.bottom = "0";
10342                     a = {height: zero};
10343                 break;
10344                 case "l":
10345                     st.right = st.top = "0";
10346                     a = {width: zero};
10347                 break;
10348                 case "r":
10349                     st.left = st.top = "0";
10350                     a = {width: zero, points: {to:[b.right, b.y]}};
10351                 break;
10352                 case "b":
10353                     st.left = st.top = "0";
10354                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10355                 break;
10356                 case "tl":
10357                     st.right = st.bottom = "0";
10358                     a = {width: zero, height: zero};
10359                 break;
10360                 case "bl":
10361                     st.right = st.top = "0";
10362                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10363                 break;
10364                 case "br":
10365                     st.left = st.top = "0";
10366                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10367                 break;
10368                 case "tr":
10369                     st.left = st.bottom = "0";
10370                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10371                 break;
10372             }
10373
10374             arguments.callee.anim = wrap.fxanim(a,
10375                 o,
10376                 'motion',
10377                 .5,
10378                 "easeOut", after);
10379         });
10380         return this;
10381     },
10382
10383         /**
10384          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10385          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10386          * The element must be removed from the DOM using the 'remove' config option if desired.
10387          * Usage:
10388          *<pre><code>
10389 // default
10390 el.puff();
10391
10392 // common config options shown with default values
10393 el.puff({
10394     easing: 'easeOut',
10395     duration: .5,
10396     remove: false,
10397     useDisplay: false
10398 });
10399 </code></pre>
10400          * @param {Object} options (optional) Object literal with any of the Fx config options
10401          * @return {Roo.Element} The Element
10402          */
10403     puff : function(o){
10404         var el = this.getFxEl();
10405         o = o || {};
10406
10407         el.queueFx(o, function(){
10408             this.clearOpacity();
10409             this.show();
10410
10411             // restore values after effect
10412             var r = this.getFxRestore();
10413             var st = this.dom.style;
10414
10415             var after = function(){
10416                 if(o.useDisplay){
10417                     el.setDisplayed(false);
10418                 }else{
10419                     el.hide();
10420                 }
10421
10422                 el.clearOpacity();
10423
10424                 el.setPositioning(r.pos);
10425                 st.width = r.width;
10426                 st.height = r.height;
10427                 st.fontSize = '';
10428                 el.afterFx(o);
10429             };
10430
10431             var width = this.getWidth();
10432             var height = this.getHeight();
10433
10434             arguments.callee.anim = this.fxanim({
10435                     width : {to: this.adjustWidth(width * 2)},
10436                     height : {to: this.adjustHeight(height * 2)},
10437                     points : {by: [-(width * .5), -(height * .5)]},
10438                     opacity : {to: 0},
10439                     fontSize: {to:200, unit: "%"}
10440                 },
10441                 o,
10442                 'motion',
10443                 .5,
10444                 "easeOut", after);
10445         });
10446         return this;
10447     },
10448
10449         /**
10450          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10451          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10452          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10453          * Usage:
10454          *<pre><code>
10455 // default
10456 el.switchOff();
10457
10458 // all config options shown with default values
10459 el.switchOff({
10460     easing: 'easeIn',
10461     duration: .3,
10462     remove: false,
10463     useDisplay: false
10464 });
10465 </code></pre>
10466          * @param {Object} options (optional) Object literal with any of the Fx config options
10467          * @return {Roo.Element} The Element
10468          */
10469     switchOff : function(o){
10470         var el = this.getFxEl();
10471         o = o || {};
10472
10473         el.queueFx(o, function(){
10474             this.clearOpacity();
10475             this.clip();
10476
10477             // restore values after effect
10478             var r = this.getFxRestore();
10479             var st = this.dom.style;
10480
10481             var after = function(){
10482                 if(o.useDisplay){
10483                     el.setDisplayed(false);
10484                 }else{
10485                     el.hide();
10486                 }
10487
10488                 el.clearOpacity();
10489                 el.setPositioning(r.pos);
10490                 st.width = r.width;
10491                 st.height = r.height;
10492
10493                 el.afterFx(o);
10494             };
10495
10496             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10497                 this.clearOpacity();
10498                 (function(){
10499                     this.fxanim({
10500                         height:{to:1},
10501                         points:{by:[0, this.getHeight() * .5]}
10502                     }, o, 'motion', 0.3, 'easeIn', after);
10503                 }).defer(100, this);
10504             });
10505         });
10506         return this;
10507     },
10508
10509     /**
10510      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10511      * changed using the "attr" config option) and then fading back to the original color. If no original
10512      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10513      * Usage:
10514 <pre><code>
10515 // default: highlight background to yellow
10516 el.highlight();
10517
10518 // custom: highlight foreground text to blue for 2 seconds
10519 el.highlight("0000ff", { attr: 'color', duration: 2 });
10520
10521 // common config options shown with default values
10522 el.highlight("ffff9c", {
10523     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10524     endColor: (current color) or "ffffff",
10525     easing: 'easeIn',
10526     duration: 1
10527 });
10528 </code></pre>
10529      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10530      * @param {Object} options (optional) Object literal with any of the Fx config options
10531      * @return {Roo.Element} The Element
10532      */ 
10533     highlight : function(color, o){
10534         var el = this.getFxEl();
10535         o = o || {};
10536
10537         el.queueFx(o, function(){
10538             color = color || "ffff9c";
10539             attr = o.attr || "backgroundColor";
10540
10541             this.clearOpacity();
10542             this.show();
10543
10544             var origColor = this.getColor(attr);
10545             var restoreColor = this.dom.style[attr];
10546             endColor = (o.endColor || origColor) || "ffffff";
10547
10548             var after = function(){
10549                 el.dom.style[attr] = restoreColor;
10550                 el.afterFx(o);
10551             };
10552
10553             var a = {};
10554             a[attr] = {from: color, to: endColor};
10555             arguments.callee.anim = this.fxanim(a,
10556                 o,
10557                 'color',
10558                 1,
10559                 'easeIn', after);
10560         });
10561         return this;
10562     },
10563
10564    /**
10565     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10566     * Usage:
10567 <pre><code>
10568 // default: a single light blue ripple
10569 el.frame();
10570
10571 // custom: 3 red ripples lasting 3 seconds total
10572 el.frame("ff0000", 3, { duration: 3 });
10573
10574 // common config options shown with default values
10575 el.frame("C3DAF9", 1, {
10576     duration: 1 //duration of entire animation (not each individual ripple)
10577     // Note: Easing is not configurable and will be ignored if included
10578 });
10579 </code></pre>
10580     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10581     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10582     * @param {Object} options (optional) Object literal with any of the Fx config options
10583     * @return {Roo.Element} The Element
10584     */
10585     frame : function(color, count, o){
10586         var el = this.getFxEl();
10587         o = o || {};
10588
10589         el.queueFx(o, function(){
10590             color = color || "#C3DAF9";
10591             if(color.length == 6){
10592                 color = "#" + color;
10593             }
10594             count = count || 1;
10595             duration = o.duration || 1;
10596             this.show();
10597
10598             var b = this.getBox();
10599             var animFn = function(){
10600                 var proxy = this.createProxy({
10601
10602                      style:{
10603                         visbility:"hidden",
10604                         position:"absolute",
10605                         "z-index":"35000", // yee haw
10606                         border:"0px solid " + color
10607                      }
10608                   });
10609                 var scale = Roo.isBorderBox ? 2 : 1;
10610                 proxy.animate({
10611                     top:{from:b.y, to:b.y - 20},
10612                     left:{from:b.x, to:b.x - 20},
10613                     borderWidth:{from:0, to:10},
10614                     opacity:{from:1, to:0},
10615                     height:{from:b.height, to:(b.height + (20*scale))},
10616                     width:{from:b.width, to:(b.width + (20*scale))}
10617                 }, duration, function(){
10618                     proxy.remove();
10619                 });
10620                 if(--count > 0){
10621                      animFn.defer((duration/2)*1000, this);
10622                 }else{
10623                     el.afterFx(o);
10624                 }
10625             };
10626             animFn.call(this);
10627         });
10628         return this;
10629     },
10630
10631    /**
10632     * Creates a pause before any subsequent queued effects begin.  If there are
10633     * no effects queued after the pause it will have no effect.
10634     * Usage:
10635 <pre><code>
10636 el.pause(1);
10637 </code></pre>
10638     * @param {Number} seconds The length of time to pause (in seconds)
10639     * @return {Roo.Element} The Element
10640     */
10641     pause : function(seconds){
10642         var el = this.getFxEl();
10643         var o = {};
10644
10645         el.queueFx(o, function(){
10646             setTimeout(function(){
10647                 el.afterFx(o);
10648             }, seconds * 1000);
10649         });
10650         return this;
10651     },
10652
10653    /**
10654     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10655     * using the "endOpacity" config option.
10656     * Usage:
10657 <pre><code>
10658 // default: fade in from opacity 0 to 100%
10659 el.fadeIn();
10660
10661 // custom: fade in from opacity 0 to 75% over 2 seconds
10662 el.fadeIn({ endOpacity: .75, duration: 2});
10663
10664 // common config options shown with default values
10665 el.fadeIn({
10666     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10667     easing: 'easeOut',
10668     duration: .5
10669 });
10670 </code></pre>
10671     * @param {Object} options (optional) Object literal with any of the Fx config options
10672     * @return {Roo.Element} The Element
10673     */
10674     fadeIn : function(o){
10675         var el = this.getFxEl();
10676         o = o || {};
10677         el.queueFx(o, function(){
10678             this.setOpacity(0);
10679             this.fixDisplay();
10680             this.dom.style.visibility = 'visible';
10681             var to = o.endOpacity || 1;
10682             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10683                 o, null, .5, "easeOut", function(){
10684                 if(to == 1){
10685                     this.clearOpacity();
10686                 }
10687                 el.afterFx(o);
10688             });
10689         });
10690         return this;
10691     },
10692
10693    /**
10694     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10695     * using the "endOpacity" config option.
10696     * Usage:
10697 <pre><code>
10698 // default: fade out from the element's current opacity to 0
10699 el.fadeOut();
10700
10701 // custom: fade out from the element's current opacity to 25% over 2 seconds
10702 el.fadeOut({ endOpacity: .25, duration: 2});
10703
10704 // common config options shown with default values
10705 el.fadeOut({
10706     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10707     easing: 'easeOut',
10708     duration: .5
10709     remove: false,
10710     useDisplay: false
10711 });
10712 </code></pre>
10713     * @param {Object} options (optional) Object literal with any of the Fx config options
10714     * @return {Roo.Element} The Element
10715     */
10716     fadeOut : function(o){
10717         var el = this.getFxEl();
10718         o = o || {};
10719         el.queueFx(o, function(){
10720             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10721                 o, null, .5, "easeOut", function(){
10722                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10723                      this.dom.style.display = "none";
10724                 }else{
10725                      this.dom.style.visibility = "hidden";
10726                 }
10727                 this.clearOpacity();
10728                 el.afterFx(o);
10729             });
10730         });
10731         return this;
10732     },
10733
10734    /**
10735     * Animates the transition of an element's dimensions from a starting height/width
10736     * to an ending height/width.
10737     * Usage:
10738 <pre><code>
10739 // change height and width to 100x100 pixels
10740 el.scale(100, 100);
10741
10742 // common config options shown with default values.  The height and width will default to
10743 // the element's existing values if passed as null.
10744 el.scale(
10745     [element's width],
10746     [element's height], {
10747     easing: 'easeOut',
10748     duration: .35
10749 });
10750 </code></pre>
10751     * @param {Number} width  The new width (pass undefined to keep the original width)
10752     * @param {Number} height  The new height (pass undefined to keep the original height)
10753     * @param {Object} options (optional) Object literal with any of the Fx config options
10754     * @return {Roo.Element} The Element
10755     */
10756     scale : function(w, h, o){
10757         this.shift(Roo.apply({}, o, {
10758             width: w,
10759             height: h
10760         }));
10761         return this;
10762     },
10763
10764    /**
10765     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10766     * Any of these properties not specified in the config object will not be changed.  This effect 
10767     * requires that at least one new dimension, position or opacity setting must be passed in on
10768     * the config object in order for the function to have any effect.
10769     * Usage:
10770 <pre><code>
10771 // slide the element horizontally to x position 200 while changing the height and opacity
10772 el.shift({ x: 200, height: 50, opacity: .8 });
10773
10774 // common config options shown with default values.
10775 el.shift({
10776     width: [element's width],
10777     height: [element's height],
10778     x: [element's x position],
10779     y: [element's y position],
10780     opacity: [element's opacity],
10781     easing: 'easeOut',
10782     duration: .35
10783 });
10784 </code></pre>
10785     * @param {Object} options  Object literal with any of the Fx config options
10786     * @return {Roo.Element} The Element
10787     */
10788     shift : function(o){
10789         var el = this.getFxEl();
10790         o = o || {};
10791         el.queueFx(o, function(){
10792             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10793             if(w !== undefined){
10794                 a.width = {to: this.adjustWidth(w)};
10795             }
10796             if(h !== undefined){
10797                 a.height = {to: this.adjustHeight(h)};
10798             }
10799             if(x !== undefined || y !== undefined){
10800                 a.points = {to: [
10801                     x !== undefined ? x : this.getX(),
10802                     y !== undefined ? y : this.getY()
10803                 ]};
10804             }
10805             if(op !== undefined){
10806                 a.opacity = {to: op};
10807             }
10808             if(o.xy !== undefined){
10809                 a.points = {to: o.xy};
10810             }
10811             arguments.callee.anim = this.fxanim(a,
10812                 o, 'motion', .35, "easeOut", function(){
10813                 el.afterFx(o);
10814             });
10815         });
10816         return this;
10817     },
10818
10819         /**
10820          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10821          * ending point of the effect.
10822          * Usage:
10823          *<pre><code>
10824 // default: slide the element downward while fading out
10825 el.ghost();
10826
10827 // custom: slide the element out to the right with a 2-second duration
10828 el.ghost('r', { duration: 2 });
10829
10830 // common config options shown with default values
10831 el.ghost('b', {
10832     easing: 'easeOut',
10833     duration: .5
10834     remove: false,
10835     useDisplay: false
10836 });
10837 </code></pre>
10838          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10839          * @param {Object} options (optional) Object literal with any of the Fx config options
10840          * @return {Roo.Element} The Element
10841          */
10842     ghost : function(anchor, o){
10843         var el = this.getFxEl();
10844         o = o || {};
10845
10846         el.queueFx(o, function(){
10847             anchor = anchor || "b";
10848
10849             // restore values after effect
10850             var r = this.getFxRestore();
10851             var w = this.getWidth(),
10852                 h = this.getHeight();
10853
10854             var st = this.dom.style;
10855
10856             var after = function(){
10857                 if(o.useDisplay){
10858                     el.setDisplayed(false);
10859                 }else{
10860                     el.hide();
10861                 }
10862
10863                 el.clearOpacity();
10864                 el.setPositioning(r.pos);
10865                 st.width = r.width;
10866                 st.height = r.height;
10867
10868                 el.afterFx(o);
10869             };
10870
10871             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10872             switch(anchor.toLowerCase()){
10873                 case "t":
10874                     pt.by = [0, -h];
10875                 break;
10876                 case "l":
10877                     pt.by = [-w, 0];
10878                 break;
10879                 case "r":
10880                     pt.by = [w, 0];
10881                 break;
10882                 case "b":
10883                     pt.by = [0, h];
10884                 break;
10885                 case "tl":
10886                     pt.by = [-w, -h];
10887                 break;
10888                 case "bl":
10889                     pt.by = [-w, h];
10890                 break;
10891                 case "br":
10892                     pt.by = [w, h];
10893                 break;
10894                 case "tr":
10895                     pt.by = [w, -h];
10896                 break;
10897             }
10898
10899             arguments.callee.anim = this.fxanim(a,
10900                 o,
10901                 'motion',
10902                 .5,
10903                 "easeOut", after);
10904         });
10905         return this;
10906     },
10907
10908         /**
10909          * Ensures that all effects queued after syncFx is called on the element are
10910          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10911          * @return {Roo.Element} The Element
10912          */
10913     syncFx : function(){
10914         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10915             block : false,
10916             concurrent : true,
10917             stopFx : false
10918         });
10919         return this;
10920     },
10921
10922         /**
10923          * Ensures that all effects queued after sequenceFx is called on the element are
10924          * run in sequence.  This is the opposite of {@link #syncFx}.
10925          * @return {Roo.Element} The Element
10926          */
10927     sequenceFx : function(){
10928         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10929             block : false,
10930             concurrent : false,
10931             stopFx : false
10932         });
10933         return this;
10934     },
10935
10936         /* @private */
10937     nextFx : function(){
10938         var ef = this.fxQueue[0];
10939         if(ef){
10940             ef.call(this);
10941         }
10942     },
10943
10944         /**
10945          * Returns true if the element has any effects actively running or queued, else returns false.
10946          * @return {Boolean} True if element has active effects, else false
10947          */
10948     hasActiveFx : function(){
10949         return this.fxQueue && this.fxQueue[0];
10950     },
10951
10952         /**
10953          * Stops any running effects and clears the element's internal effects queue if it contains
10954          * any additional effects that haven't started yet.
10955          * @return {Roo.Element} The Element
10956          */
10957     stopFx : function(){
10958         if(this.hasActiveFx()){
10959             var cur = this.fxQueue[0];
10960             if(cur && cur.anim && cur.anim.isAnimated()){
10961                 this.fxQueue = [cur]; // clear out others
10962                 cur.anim.stop(true);
10963             }
10964         }
10965         return this;
10966     },
10967
10968         /* @private */
10969     beforeFx : function(o){
10970         if(this.hasActiveFx() && !o.concurrent){
10971            if(o.stopFx){
10972                this.stopFx();
10973                return true;
10974            }
10975            return false;
10976         }
10977         return true;
10978     },
10979
10980         /**
10981          * Returns true if the element is currently blocking so that no other effect can be queued
10982          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10983          * used to ensure that an effect initiated by a user action runs to completion prior to the
10984          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10985          * @return {Boolean} True if blocking, else false
10986          */
10987     hasFxBlock : function(){
10988         var q = this.fxQueue;
10989         return q && q[0] && q[0].block;
10990     },
10991
10992         /* @private */
10993     queueFx : function(o, fn){
10994         if(!this.fxQueue){
10995             this.fxQueue = [];
10996         }
10997         if(!this.hasFxBlock()){
10998             Roo.applyIf(o, this.fxDefaults);
10999             if(!o.concurrent){
11000                 var run = this.beforeFx(o);
11001                 fn.block = o.block;
11002                 this.fxQueue.push(fn);
11003                 if(run){
11004                     this.nextFx();
11005                 }
11006             }else{
11007                 fn.call(this);
11008             }
11009         }
11010         return this;
11011     },
11012
11013         /* @private */
11014     fxWrap : function(pos, o, vis){
11015         var wrap;
11016         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11017             var wrapXY;
11018             if(o.fixPosition){
11019                 wrapXY = this.getXY();
11020             }
11021             var div = document.createElement("div");
11022             div.style.visibility = vis;
11023             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11024             wrap.setPositioning(pos);
11025             if(wrap.getStyle("position") == "static"){
11026                 wrap.position("relative");
11027             }
11028             this.clearPositioning('auto');
11029             wrap.clip();
11030             wrap.dom.appendChild(this.dom);
11031             if(wrapXY){
11032                 wrap.setXY(wrapXY);
11033             }
11034         }
11035         return wrap;
11036     },
11037
11038         /* @private */
11039     fxUnwrap : function(wrap, pos, o){
11040         this.clearPositioning();
11041         this.setPositioning(pos);
11042         if(!o.wrap){
11043             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11044             wrap.remove();
11045         }
11046     },
11047
11048         /* @private */
11049     getFxRestore : function(){
11050         var st = this.dom.style;
11051         return {pos: this.getPositioning(), width: st.width, height : st.height};
11052     },
11053
11054         /* @private */
11055     afterFx : function(o){
11056         if(o.afterStyle){
11057             this.applyStyles(o.afterStyle);
11058         }
11059         if(o.afterCls){
11060             this.addClass(o.afterCls);
11061         }
11062         if(o.remove === true){
11063             this.remove();
11064         }
11065         Roo.callback(o.callback, o.scope, [this]);
11066         if(!o.concurrent){
11067             this.fxQueue.shift();
11068             this.nextFx();
11069         }
11070     },
11071
11072         /* @private */
11073     getFxEl : function(){ // support for composite element fx
11074         return Roo.get(this.dom);
11075     },
11076
11077         /* @private */
11078     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11079         animType = animType || 'run';
11080         opt = opt || {};
11081         var anim = Roo.lib.Anim[animType](
11082             this.dom, args,
11083             (opt.duration || defaultDur) || .35,
11084             (opt.easing || defaultEase) || 'easeOut',
11085             function(){
11086                 Roo.callback(cb, this);
11087             },
11088             this
11089         );
11090         opt.anim = anim;
11091         return anim;
11092     }
11093 };
11094
11095 // backwords compat
11096 Roo.Fx.resize = Roo.Fx.scale;
11097
11098 //When included, Roo.Fx is automatically applied to Element so that all basic
11099 //effects are available directly via the Element API
11100 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11101  * Based on:
11102  * Ext JS Library 1.1.1
11103  * Copyright(c) 2006-2007, Ext JS, LLC.
11104  *
11105  * Originally Released Under LGPL - original licence link has changed is not relivant.
11106  *
11107  * Fork - LGPL
11108  * <script type="text/javascript">
11109  */
11110
11111
11112 /**
11113  * @class Roo.CompositeElement
11114  * Standard composite class. Creates a Roo.Element for every element in the collection.
11115  * <br><br>
11116  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11117  * actions will be performed on all the elements in this collection.</b>
11118  * <br><br>
11119  * All methods return <i>this</i> and can be chained.
11120  <pre><code>
11121  var els = Roo.select("#some-el div.some-class", true);
11122  // or select directly from an existing element
11123  var el = Roo.get('some-el');
11124  el.select('div.some-class', true);
11125
11126  els.setWidth(100); // all elements become 100 width
11127  els.hide(true); // all elements fade out and hide
11128  // or
11129  els.setWidth(100).hide(true);
11130  </code></pre>
11131  */
11132 Roo.CompositeElement = function(els){
11133     this.elements = [];
11134     this.addElements(els);
11135 };
11136 Roo.CompositeElement.prototype = {
11137     isComposite: true,
11138     addElements : function(els){
11139         if(!els) {
11140             return this;
11141         }
11142         if(typeof els == "string"){
11143             els = Roo.Element.selectorFunction(els);
11144         }
11145         var yels = this.elements;
11146         var index = yels.length-1;
11147         for(var i = 0, len = els.length; i < len; i++) {
11148                 yels[++index] = Roo.get(els[i]);
11149         }
11150         return this;
11151     },
11152
11153     /**
11154     * Clears this composite and adds the elements returned by the passed selector.
11155     * @param {String/Array} els A string CSS selector, an array of elements or an element
11156     * @return {CompositeElement} this
11157     */
11158     fill : function(els){
11159         this.elements = [];
11160         this.add(els);
11161         return this;
11162     },
11163
11164     /**
11165     * Filters this composite to only elements that match the passed selector.
11166     * @param {String} selector A string CSS selector
11167     * @param {Boolean} inverse return inverse filter (not matches)
11168     * @return {CompositeElement} this
11169     */
11170     filter : function(selector, inverse){
11171         var els = [];
11172         inverse = inverse || false;
11173         this.each(function(el){
11174             var match = inverse ? !el.is(selector) : el.is(selector);
11175             if(match){
11176                 els[els.length] = el.dom;
11177             }
11178         });
11179         this.fill(els);
11180         return this;
11181     },
11182
11183     invoke : function(fn, args){
11184         var els = this.elements;
11185         for(var i = 0, len = els.length; i < len; i++) {
11186                 Roo.Element.prototype[fn].apply(els[i], args);
11187         }
11188         return this;
11189     },
11190     /**
11191     * Adds elements to this composite.
11192     * @param {String/Array} els A string CSS selector, an array of elements or an element
11193     * @return {CompositeElement} this
11194     */
11195     add : function(els){
11196         if(typeof els == "string"){
11197             this.addElements(Roo.Element.selectorFunction(els));
11198         }else if(els.length !== undefined){
11199             this.addElements(els);
11200         }else{
11201             this.addElements([els]);
11202         }
11203         return this;
11204     },
11205     /**
11206     * Calls the passed function passing (el, this, index) for each element in this composite.
11207     * @param {Function} fn The function to call
11208     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11209     * @return {CompositeElement} this
11210     */
11211     each : function(fn, scope){
11212         var els = this.elements;
11213         for(var i = 0, len = els.length; i < len; i++){
11214             if(fn.call(scope || els[i], els[i], this, i) === false) {
11215                 break;
11216             }
11217         }
11218         return this;
11219     },
11220
11221     /**
11222      * Returns the Element object at the specified index
11223      * @param {Number} index
11224      * @return {Roo.Element}
11225      */
11226     item : function(index){
11227         return this.elements[index] || null;
11228     },
11229
11230     /**
11231      * Returns the first Element
11232      * @return {Roo.Element}
11233      */
11234     first : function(){
11235         return this.item(0);
11236     },
11237
11238     /**
11239      * Returns the last Element
11240      * @return {Roo.Element}
11241      */
11242     last : function(){
11243         return this.item(this.elements.length-1);
11244     },
11245
11246     /**
11247      * Returns the number of elements in this composite
11248      * @return Number
11249      */
11250     getCount : function(){
11251         return this.elements.length;
11252     },
11253
11254     /**
11255      * Returns true if this composite contains the passed element
11256      * @return Boolean
11257      */
11258     contains : function(el){
11259         return this.indexOf(el) !== -1;
11260     },
11261
11262     /**
11263      * Returns true if this composite contains the passed element
11264      * @return Boolean
11265      */
11266     indexOf : function(el){
11267         return this.elements.indexOf(Roo.get(el));
11268     },
11269
11270
11271     /**
11272     * Removes the specified element(s).
11273     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11274     * or an array of any of those.
11275     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11276     * @return {CompositeElement} this
11277     */
11278     removeElement : function(el, removeDom){
11279         if(el instanceof Array){
11280             for(var i = 0, len = el.length; i < len; i++){
11281                 this.removeElement(el[i]);
11282             }
11283             return this;
11284         }
11285         var index = typeof el == 'number' ? el : this.indexOf(el);
11286         if(index !== -1){
11287             if(removeDom){
11288                 var d = this.elements[index];
11289                 if(d.dom){
11290                     d.remove();
11291                 }else{
11292                     d.parentNode.removeChild(d);
11293                 }
11294             }
11295             this.elements.splice(index, 1);
11296         }
11297         return this;
11298     },
11299
11300     /**
11301     * Replaces the specified element with the passed element.
11302     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11303     * to replace.
11304     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11305     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11306     * @return {CompositeElement} this
11307     */
11308     replaceElement : function(el, replacement, domReplace){
11309         var index = typeof el == 'number' ? el : this.indexOf(el);
11310         if(index !== -1){
11311             if(domReplace){
11312                 this.elements[index].replaceWith(replacement);
11313             }else{
11314                 this.elements.splice(index, 1, Roo.get(replacement))
11315             }
11316         }
11317         return this;
11318     },
11319
11320     /**
11321      * Removes all elements.
11322      */
11323     clear : function(){
11324         this.elements = [];
11325     }
11326 };
11327 (function(){
11328     Roo.CompositeElement.createCall = function(proto, fnName){
11329         if(!proto[fnName]){
11330             proto[fnName] = function(){
11331                 return this.invoke(fnName, arguments);
11332             };
11333         }
11334     };
11335     for(var fnName in Roo.Element.prototype){
11336         if(typeof Roo.Element.prototype[fnName] == "function"){
11337             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11338         }
11339     };
11340 })();
11341 /*
11342  * Based on:
11343  * Ext JS Library 1.1.1
11344  * Copyright(c) 2006-2007, Ext JS, LLC.
11345  *
11346  * Originally Released Under LGPL - original licence link has changed is not relivant.
11347  *
11348  * Fork - LGPL
11349  * <script type="text/javascript">
11350  */
11351
11352 /**
11353  * @class Roo.CompositeElementLite
11354  * @extends Roo.CompositeElement
11355  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11356  <pre><code>
11357  var els = Roo.select("#some-el div.some-class");
11358  // or select directly from an existing element
11359  var el = Roo.get('some-el');
11360  el.select('div.some-class');
11361
11362  els.setWidth(100); // all elements become 100 width
11363  els.hide(true); // all elements fade out and hide
11364  // or
11365  els.setWidth(100).hide(true);
11366  </code></pre><br><br>
11367  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11368  * actions will be performed on all the elements in this collection.</b>
11369  */
11370 Roo.CompositeElementLite = function(els){
11371     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11372     this.el = new Roo.Element.Flyweight();
11373 };
11374 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11375     addElements : function(els){
11376         if(els){
11377             if(els instanceof Array){
11378                 this.elements = this.elements.concat(els);
11379             }else{
11380                 var yels = this.elements;
11381                 var index = yels.length-1;
11382                 for(var i = 0, len = els.length; i < len; i++) {
11383                     yels[++index] = els[i];
11384                 }
11385             }
11386         }
11387         return this;
11388     },
11389     invoke : function(fn, args){
11390         var els = this.elements;
11391         var el = this.el;
11392         for(var i = 0, len = els.length; i < len; i++) {
11393             el.dom = els[i];
11394                 Roo.Element.prototype[fn].apply(el, args);
11395         }
11396         return this;
11397     },
11398     /**
11399      * Returns a flyweight Element of the dom element object at the specified index
11400      * @param {Number} index
11401      * @return {Roo.Element}
11402      */
11403     item : function(index){
11404         if(!this.elements[index]){
11405             return null;
11406         }
11407         this.el.dom = this.elements[index];
11408         return this.el;
11409     },
11410
11411     // fixes scope with flyweight
11412     addListener : function(eventName, handler, scope, opt){
11413         var els = this.elements;
11414         for(var i = 0, len = els.length; i < len; i++) {
11415             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11416         }
11417         return this;
11418     },
11419
11420     /**
11421     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11422     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11423     * a reference to the dom node, use el.dom.</b>
11424     * @param {Function} fn The function to call
11425     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11426     * @return {CompositeElement} this
11427     */
11428     each : function(fn, scope){
11429         var els = this.elements;
11430         var el = this.el;
11431         for(var i = 0, len = els.length; i < len; i++){
11432             el.dom = els[i];
11433                 if(fn.call(scope || el, el, this, i) === false){
11434                 break;
11435             }
11436         }
11437         return this;
11438     },
11439
11440     indexOf : function(el){
11441         return this.elements.indexOf(Roo.getDom(el));
11442     },
11443
11444     replaceElement : function(el, replacement, domReplace){
11445         var index = typeof el == 'number' ? el : this.indexOf(el);
11446         if(index !== -1){
11447             replacement = Roo.getDom(replacement);
11448             if(domReplace){
11449                 var d = this.elements[index];
11450                 d.parentNode.insertBefore(replacement, d);
11451                 d.parentNode.removeChild(d);
11452             }
11453             this.elements.splice(index, 1, replacement);
11454         }
11455         return this;
11456     }
11457 });
11458 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11459
11460 /*
11461  * Based on:
11462  * Ext JS Library 1.1.1
11463  * Copyright(c) 2006-2007, Ext JS, LLC.
11464  *
11465  * Originally Released Under LGPL - original licence link has changed is not relivant.
11466  *
11467  * Fork - LGPL
11468  * <script type="text/javascript">
11469  */
11470
11471  
11472
11473 /**
11474  * @class Roo.data.Connection
11475  * @extends Roo.util.Observable
11476  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11477  * either to a configured URL, or to a URL specified at request time.<br><br>
11478  * <p>
11479  * Requests made by this class are asynchronous, and will return immediately. No data from
11480  * the server will be available to the statement immediately following the {@link #request} call.
11481  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11482  * <p>
11483  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11484  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11485  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11486  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11487  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11488  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11489  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11490  * standard DOM methods.
11491  * @constructor
11492  * @param {Object} config a configuration object.
11493  */
11494 Roo.data.Connection = function(config){
11495     Roo.apply(this, config);
11496     this.addEvents({
11497         /**
11498          * @event beforerequest
11499          * Fires before a network request is made to retrieve a data object.
11500          * @param {Connection} conn This Connection object.
11501          * @param {Object} options The options config object passed to the {@link #request} method.
11502          */
11503         "beforerequest" : true,
11504         /**
11505          * @event requestcomplete
11506          * Fires if the request was successfully completed.
11507          * @param {Connection} conn This Connection object.
11508          * @param {Object} response The XHR object containing the response data.
11509          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11510          * @param {Object} options The options config object passed to the {@link #request} method.
11511          */
11512         "requestcomplete" : true,
11513         /**
11514          * @event requestexception
11515          * Fires if an error HTTP status was returned from the server.
11516          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11517          * @param {Connection} conn This Connection object.
11518          * @param {Object} response The XHR object containing the response data.
11519          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11520          * @param {Object} options The options config object passed to the {@link #request} method.
11521          */
11522         "requestexception" : true
11523     });
11524     Roo.data.Connection.superclass.constructor.call(this);
11525 };
11526
11527 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11528     /**
11529      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11530      */
11531     /**
11532      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11533      * extra parameters to each request made by this object. (defaults to undefined)
11534      */
11535     /**
11536      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11537      *  to each request made by this object. (defaults to undefined)
11538      */
11539     /**
11540      * @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)
11541      */
11542     /**
11543      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11544      */
11545     timeout : 30000,
11546     /**
11547      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11548      * @type Boolean
11549      */
11550     autoAbort:false,
11551
11552     /**
11553      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11554      * @type Boolean
11555      */
11556     disableCaching: true,
11557
11558     /**
11559      * Sends an HTTP request to a remote server.
11560      * @param {Object} options An object which may contain the following properties:<ul>
11561      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11562      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11563      * request, a url encoded string or a function to call to get either.</li>
11564      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11565      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11566      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11567      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11568      * <li>options {Object} The parameter to the request call.</li>
11569      * <li>success {Boolean} True if the request succeeded.</li>
11570      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11571      * </ul></li>
11572      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11573      * The callback is passed the following parameters:<ul>
11574      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11575      * <li>options {Object} The parameter to the request call.</li>
11576      * </ul></li>
11577      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11578      * The callback is passed the following parameters:<ul>
11579      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11580      * <li>options {Object} The parameter to the request call.</li>
11581      * </ul></li>
11582      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11583      * for the callback function. Defaults to the browser window.</li>
11584      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11585      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11586      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11587      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11588      * params for the post data. Any params will be appended to the URL.</li>
11589      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11590      * </ul>
11591      * @return {Number} transactionId
11592      */
11593     request : function(o){
11594         if(this.fireEvent("beforerequest", this, o) !== false){
11595             var p = o.params;
11596
11597             if(typeof p == "function"){
11598                 p = p.call(o.scope||window, o);
11599             }
11600             if(typeof p == "object"){
11601                 p = Roo.urlEncode(o.params);
11602             }
11603             if(this.extraParams){
11604                 var extras = Roo.urlEncode(this.extraParams);
11605                 p = p ? (p + '&' + extras) : extras;
11606             }
11607
11608             var url = o.url || this.url;
11609             if(typeof url == 'function'){
11610                 url = url.call(o.scope||window, o);
11611             }
11612
11613             if(o.form){
11614                 var form = Roo.getDom(o.form);
11615                 url = url || form.action;
11616
11617                 var enctype = form.getAttribute("enctype");
11618                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11619                     return this.doFormUpload(o, p, url);
11620                 }
11621                 var f = Roo.lib.Ajax.serializeForm(form);
11622                 p = p ? (p + '&' + f) : f;
11623             }
11624
11625             var hs = o.headers;
11626             if(this.defaultHeaders){
11627                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11628                 if(!o.headers){
11629                     o.headers = hs;
11630                 }
11631             }
11632
11633             var cb = {
11634                 success: this.handleResponse,
11635                 failure: this.handleFailure,
11636                 scope: this,
11637                 argument: {options: o},
11638                 timeout : o.timeout || this.timeout
11639             };
11640
11641             var method = o.method||this.method||(p ? "POST" : "GET");
11642
11643             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11644                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11645             }
11646
11647             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11648                 if(o.autoAbort){
11649                     this.abort();
11650                 }
11651             }else if(this.autoAbort !== false){
11652                 this.abort();
11653             }
11654
11655             if((method == 'GET' && p) || o.xmlData){
11656                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11657                 p = '';
11658             }
11659             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11660             return this.transId;
11661         }else{
11662             Roo.callback(o.callback, o.scope, [o, null, null]);
11663             return null;
11664         }
11665     },
11666
11667     /**
11668      * Determine whether this object has a request outstanding.
11669      * @param {Number} transactionId (Optional) defaults to the last transaction
11670      * @return {Boolean} True if there is an outstanding request.
11671      */
11672     isLoading : function(transId){
11673         if(transId){
11674             return Roo.lib.Ajax.isCallInProgress(transId);
11675         }else{
11676             return this.transId ? true : false;
11677         }
11678     },
11679
11680     /**
11681      * Aborts any outstanding request.
11682      * @param {Number} transactionId (Optional) defaults to the last transaction
11683      */
11684     abort : function(transId){
11685         if(transId || this.isLoading()){
11686             Roo.lib.Ajax.abort(transId || this.transId);
11687         }
11688     },
11689
11690     // private
11691     handleResponse : function(response){
11692         this.transId = false;
11693         var options = response.argument.options;
11694         response.argument = options ? options.argument : null;
11695         this.fireEvent("requestcomplete", this, response, options);
11696         Roo.callback(options.success, options.scope, [response, options]);
11697         Roo.callback(options.callback, options.scope, [options, true, response]);
11698     },
11699
11700     // private
11701     handleFailure : function(response, e){
11702         this.transId = false;
11703         var options = response.argument.options;
11704         response.argument = options ? options.argument : null;
11705         this.fireEvent("requestexception", this, response, options, e);
11706         Roo.callback(options.failure, options.scope, [response, options]);
11707         Roo.callback(options.callback, options.scope, [options, false, response]);
11708     },
11709
11710     // private
11711     doFormUpload : function(o, ps, url){
11712         var id = Roo.id();
11713         var frame = document.createElement('iframe');
11714         frame.id = id;
11715         frame.name = id;
11716         frame.className = 'x-hidden';
11717         if(Roo.isIE){
11718             frame.src = Roo.SSL_SECURE_URL;
11719         }
11720         document.body.appendChild(frame);
11721
11722         if(Roo.isIE){
11723            document.frames[id].name = id;
11724         }
11725
11726         var form = Roo.getDom(o.form);
11727         form.target = id;
11728         form.method = 'POST';
11729         form.enctype = form.encoding = 'multipart/form-data';
11730         if(url){
11731             form.action = url;
11732         }
11733
11734         var hiddens, hd;
11735         if(ps){ // add dynamic params
11736             hiddens = [];
11737             ps = Roo.urlDecode(ps, false);
11738             for(var k in ps){
11739                 if(ps.hasOwnProperty(k)){
11740                     hd = document.createElement('input');
11741                     hd.type = 'hidden';
11742                     hd.name = k;
11743                     hd.value = ps[k];
11744                     form.appendChild(hd);
11745                     hiddens.push(hd);
11746                 }
11747             }
11748         }
11749
11750         function cb(){
11751             var r = {  // bogus response object
11752                 responseText : '',
11753                 responseXML : null
11754             };
11755
11756             r.argument = o ? o.argument : null;
11757
11758             try { //
11759                 var doc;
11760                 if(Roo.isIE){
11761                     doc = frame.contentWindow.document;
11762                 }else {
11763                     doc = (frame.contentDocument || window.frames[id].document);
11764                 }
11765                 if(doc && doc.body){
11766                     r.responseText = doc.body.innerHTML;
11767                 }
11768                 if(doc && doc.XMLDocument){
11769                     r.responseXML = doc.XMLDocument;
11770                 }else {
11771                     r.responseXML = doc;
11772                 }
11773             }
11774             catch(e) {
11775                 // ignore
11776             }
11777
11778             Roo.EventManager.removeListener(frame, 'load', cb, this);
11779
11780             this.fireEvent("requestcomplete", this, r, o);
11781             Roo.callback(o.success, o.scope, [r, o]);
11782             Roo.callback(o.callback, o.scope, [o, true, r]);
11783
11784             setTimeout(function(){document.body.removeChild(frame);}, 100);
11785         }
11786
11787         Roo.EventManager.on(frame, 'load', cb, this);
11788         form.submit();
11789
11790         if(hiddens){ // remove dynamic params
11791             for(var i = 0, len = hiddens.length; i < len; i++){
11792                 form.removeChild(hiddens[i]);
11793             }
11794         }
11795     }
11796 });
11797 /*
11798  * Based on:
11799  * Ext JS Library 1.1.1
11800  * Copyright(c) 2006-2007, Ext JS, LLC.
11801  *
11802  * Originally Released Under LGPL - original licence link has changed is not relivant.
11803  *
11804  * Fork - LGPL
11805  * <script type="text/javascript">
11806  */
11807  
11808 /**
11809  * Global Ajax request class.
11810  * 
11811  * @class Roo.Ajax
11812  * @extends Roo.data.Connection
11813  * @static
11814  * 
11815  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11816  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11817  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11818  * @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)
11819  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11820  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11821  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11822  */
11823 Roo.Ajax = new Roo.data.Connection({
11824     // fix up the docs
11825     /**
11826      * @scope Roo.Ajax
11827      * @type {Boolear} 
11828      */
11829     autoAbort : false,
11830
11831     /**
11832      * Serialize the passed form into a url encoded string
11833      * @scope Roo.Ajax
11834      * @param {String/HTMLElement} form
11835      * @return {String}
11836      */
11837     serializeForm : function(form){
11838         return Roo.lib.Ajax.serializeForm(form);
11839     }
11840 });/*
11841  * Based on:
11842  * Ext JS Library 1.1.1
11843  * Copyright(c) 2006-2007, Ext JS, LLC.
11844  *
11845  * Originally Released Under LGPL - original licence link has changed is not relivant.
11846  *
11847  * Fork - LGPL
11848  * <script type="text/javascript">
11849  */
11850
11851  
11852 /**
11853  * @class Roo.UpdateManager
11854  * @extends Roo.util.Observable
11855  * Provides AJAX-style update for Element object.<br><br>
11856  * Usage:<br>
11857  * <pre><code>
11858  * // Get it from a Roo.Element object
11859  * var el = Roo.get("foo");
11860  * var mgr = el.getUpdateManager();
11861  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11862  * ...
11863  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11864  * <br>
11865  * // or directly (returns the same UpdateManager instance)
11866  * var mgr = new Roo.UpdateManager("myElementId");
11867  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11868  * mgr.on("update", myFcnNeedsToKnow);
11869  * <br>
11870    // short handed call directly from the element object
11871    Roo.get("foo").load({
11872         url: "bar.php",
11873         scripts:true,
11874         params: "for=bar",
11875         text: "Loading Foo..."
11876    });
11877  * </code></pre>
11878  * @constructor
11879  * Create new UpdateManager directly.
11880  * @param {String/HTMLElement/Roo.Element} el The element to update
11881  * @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).
11882  */
11883 Roo.UpdateManager = function(el, forceNew){
11884     el = Roo.get(el);
11885     if(!forceNew && el.updateManager){
11886         return el.updateManager;
11887     }
11888     /**
11889      * The Element object
11890      * @type Roo.Element
11891      */
11892     this.el = el;
11893     /**
11894      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11895      * @type String
11896      */
11897     this.defaultUrl = null;
11898
11899     this.addEvents({
11900         /**
11901          * @event beforeupdate
11902          * Fired before an update is made, return false from your handler and the update is cancelled.
11903          * @param {Roo.Element} el
11904          * @param {String/Object/Function} url
11905          * @param {String/Object} params
11906          */
11907         "beforeupdate": true,
11908         /**
11909          * @event update
11910          * Fired after successful update is made.
11911          * @param {Roo.Element} el
11912          * @param {Object} oResponseObject The response Object
11913          */
11914         "update": true,
11915         /**
11916          * @event failure
11917          * Fired on update failure.
11918          * @param {Roo.Element} el
11919          * @param {Object} oResponseObject The response Object
11920          */
11921         "failure": true
11922     });
11923     var d = Roo.UpdateManager.defaults;
11924     /**
11925      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11926      * @type String
11927      */
11928     this.sslBlankUrl = d.sslBlankUrl;
11929     /**
11930      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11931      * @type Boolean
11932      */
11933     this.disableCaching = d.disableCaching;
11934     /**
11935      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11936      * @type String
11937      */
11938     this.indicatorText = d.indicatorText;
11939     /**
11940      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11941      * @type String
11942      */
11943     this.showLoadIndicator = d.showLoadIndicator;
11944     /**
11945      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11946      * @type Number
11947      */
11948     this.timeout = d.timeout;
11949
11950     /**
11951      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11952      * @type Boolean
11953      */
11954     this.loadScripts = d.loadScripts;
11955
11956     /**
11957      * Transaction object of current executing transaction
11958      */
11959     this.transaction = null;
11960
11961     /**
11962      * @private
11963      */
11964     this.autoRefreshProcId = null;
11965     /**
11966      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11967      * @type Function
11968      */
11969     this.refreshDelegate = this.refresh.createDelegate(this);
11970     /**
11971      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11972      * @type Function
11973      */
11974     this.updateDelegate = this.update.createDelegate(this);
11975     /**
11976      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11977      * @type Function
11978      */
11979     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11980     /**
11981      * @private
11982      */
11983     this.successDelegate = this.processSuccess.createDelegate(this);
11984     /**
11985      * @private
11986      */
11987     this.failureDelegate = this.processFailure.createDelegate(this);
11988
11989     if(!this.renderer){
11990      /**
11991       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11992       */
11993     this.renderer = new Roo.UpdateManager.BasicRenderer();
11994     }
11995     
11996     Roo.UpdateManager.superclass.constructor.call(this);
11997 };
11998
11999 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12000     /**
12001      * Get the Element this UpdateManager is bound to
12002      * @return {Roo.Element} The element
12003      */
12004     getEl : function(){
12005         return this.el;
12006     },
12007     /**
12008      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12009      * @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:
12010 <pre><code>
12011 um.update({<br/>
12012     url: "your-url.php",<br/>
12013     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12014     callback: yourFunction,<br/>
12015     scope: yourObject, //(optional scope)  <br/>
12016     discardUrl: false, <br/>
12017     nocache: false,<br/>
12018     text: "Loading...",<br/>
12019     timeout: 30,<br/>
12020     scripts: false<br/>
12021 });
12022 </code></pre>
12023      * The only required property is url. The optional properties nocache, text and scripts
12024      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12025      * @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}
12026      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12027      * @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.
12028      */
12029     update : function(url, params, callback, discardUrl){
12030         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12031             var method = this.method,
12032                 cfg;
12033             if(typeof url == "object"){ // must be config object
12034                 cfg = url;
12035                 url = cfg.url;
12036                 params = params || cfg.params;
12037                 callback = callback || cfg.callback;
12038                 discardUrl = discardUrl || cfg.discardUrl;
12039                 if(callback && cfg.scope){
12040                     callback = callback.createDelegate(cfg.scope);
12041                 }
12042                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12043                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12044                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12045                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12046                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12047             }
12048             this.showLoading();
12049             if(!discardUrl){
12050                 this.defaultUrl = url;
12051             }
12052             if(typeof url == "function"){
12053                 url = url.call(this);
12054             }
12055
12056             method = method || (params ? "POST" : "GET");
12057             if(method == "GET"){
12058                 url = this.prepareUrl(url);
12059             }
12060
12061             var o = Roo.apply(cfg ||{}, {
12062                 url : url,
12063                 params: params,
12064                 success: this.successDelegate,
12065                 failure: this.failureDelegate,
12066                 callback: undefined,
12067                 timeout: (this.timeout*1000),
12068                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12069             });
12070             Roo.log("updated manager called with timeout of " + o.timeout);
12071             this.transaction = Roo.Ajax.request(o);
12072         }
12073     },
12074
12075     /**
12076      * 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.
12077      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12078      * @param {String/HTMLElement} form The form Id or form element
12079      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12080      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12081      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12082      */
12083     formUpdate : function(form, url, reset, callback){
12084         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12085             if(typeof url == "function"){
12086                 url = url.call(this);
12087             }
12088             form = Roo.getDom(form);
12089             this.transaction = Roo.Ajax.request({
12090                 form: form,
12091                 url:url,
12092                 success: this.successDelegate,
12093                 failure: this.failureDelegate,
12094                 timeout: (this.timeout*1000),
12095                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12096             });
12097             this.showLoading.defer(1, this);
12098         }
12099     },
12100
12101     /**
12102      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12103      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12104      */
12105     refresh : function(callback){
12106         if(this.defaultUrl == null){
12107             return;
12108         }
12109         this.update(this.defaultUrl, null, callback, true);
12110     },
12111
12112     /**
12113      * Set this element to auto refresh.
12114      * @param {Number} interval How often to update (in seconds).
12115      * @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)
12116      * @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}
12117      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12118      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12119      */
12120     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12121         if(refreshNow){
12122             this.update(url || this.defaultUrl, params, callback, true);
12123         }
12124         if(this.autoRefreshProcId){
12125             clearInterval(this.autoRefreshProcId);
12126         }
12127         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12128     },
12129
12130     /**
12131      * Stop auto refresh on this element.
12132      */
12133      stopAutoRefresh : function(){
12134         if(this.autoRefreshProcId){
12135             clearInterval(this.autoRefreshProcId);
12136             delete this.autoRefreshProcId;
12137         }
12138     },
12139
12140     isAutoRefreshing : function(){
12141        return this.autoRefreshProcId ? true : false;
12142     },
12143     /**
12144      * Called to update the element to "Loading" state. Override to perform custom action.
12145      */
12146     showLoading : function(){
12147         if(this.showLoadIndicator){
12148             this.el.update(this.indicatorText);
12149         }
12150     },
12151
12152     /**
12153      * Adds unique parameter to query string if disableCaching = true
12154      * @private
12155      */
12156     prepareUrl : function(url){
12157         if(this.disableCaching){
12158             var append = "_dc=" + (new Date().getTime());
12159             if(url.indexOf("?") !== -1){
12160                 url += "&" + append;
12161             }else{
12162                 url += "?" + append;
12163             }
12164         }
12165         return url;
12166     },
12167
12168     /**
12169      * @private
12170      */
12171     processSuccess : function(response){
12172         this.transaction = null;
12173         if(response.argument.form && response.argument.reset){
12174             try{ // put in try/catch since some older FF releases had problems with this
12175                 response.argument.form.reset();
12176             }catch(e){}
12177         }
12178         if(this.loadScripts){
12179             this.renderer.render(this.el, response, this,
12180                 this.updateComplete.createDelegate(this, [response]));
12181         }else{
12182             this.renderer.render(this.el, response, this);
12183             this.updateComplete(response);
12184         }
12185     },
12186
12187     updateComplete : function(response){
12188         this.fireEvent("update", this.el, response);
12189         if(typeof response.argument.callback == "function"){
12190             response.argument.callback(this.el, true, response);
12191         }
12192     },
12193
12194     /**
12195      * @private
12196      */
12197     processFailure : function(response){
12198         this.transaction = null;
12199         this.fireEvent("failure", this.el, response);
12200         if(typeof response.argument.callback == "function"){
12201             response.argument.callback(this.el, false, response);
12202         }
12203     },
12204
12205     /**
12206      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12207      * @param {Object} renderer The object implementing the render() method
12208      */
12209     setRenderer : function(renderer){
12210         this.renderer = renderer;
12211     },
12212
12213     getRenderer : function(){
12214        return this.renderer;
12215     },
12216
12217     /**
12218      * Set the defaultUrl used for updates
12219      * @param {String/Function} defaultUrl The url or a function to call to get the url
12220      */
12221     setDefaultUrl : function(defaultUrl){
12222         this.defaultUrl = defaultUrl;
12223     },
12224
12225     /**
12226      * Aborts the executing transaction
12227      */
12228     abort : function(){
12229         if(this.transaction){
12230             Roo.Ajax.abort(this.transaction);
12231         }
12232     },
12233
12234     /**
12235      * Returns true if an update is in progress
12236      * @return {Boolean}
12237      */
12238     isUpdating : function(){
12239         if(this.transaction){
12240             return Roo.Ajax.isLoading(this.transaction);
12241         }
12242         return false;
12243     }
12244 });
12245
12246 /**
12247  * @class Roo.UpdateManager.defaults
12248  * @static (not really - but it helps the doc tool)
12249  * The defaults collection enables customizing the default properties of UpdateManager
12250  */
12251    Roo.UpdateManager.defaults = {
12252        /**
12253          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12254          * @type Number
12255          */
12256          timeout : 30,
12257
12258          /**
12259          * True to process scripts by default (Defaults to false).
12260          * @type Boolean
12261          */
12262         loadScripts : false,
12263
12264         /**
12265         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12266         * @type String
12267         */
12268         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12269         /**
12270          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12271          * @type Boolean
12272          */
12273         disableCaching : false,
12274         /**
12275          * Whether to show indicatorText when loading (Defaults to true).
12276          * @type Boolean
12277          */
12278         showLoadIndicator : true,
12279         /**
12280          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12281          * @type String
12282          */
12283         indicatorText : '<div class="loading-indicator">Loading...</div>'
12284    };
12285
12286 /**
12287  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12288  *Usage:
12289  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12290  * @param {String/HTMLElement/Roo.Element} el The element to update
12291  * @param {String} url The url
12292  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12293  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12294  * @static
12295  * @deprecated
12296  * @member Roo.UpdateManager
12297  */
12298 Roo.UpdateManager.updateElement = function(el, url, params, options){
12299     var um = Roo.get(el, true).getUpdateManager();
12300     Roo.apply(um, options);
12301     um.update(url, params, options ? options.callback : null);
12302 };
12303 // alias for backwards compat
12304 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12305 /**
12306  * @class Roo.UpdateManager.BasicRenderer
12307  * Default Content renderer. Updates the elements innerHTML with the responseText.
12308  */
12309 Roo.UpdateManager.BasicRenderer = function(){};
12310
12311 Roo.UpdateManager.BasicRenderer.prototype = {
12312     /**
12313      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12314      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12315      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12316      * @param {Roo.Element} el The element being rendered
12317      * @param {Object} response The YUI Connect response object
12318      * @param {UpdateManager} updateManager The calling update manager
12319      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12320      */
12321      render : function(el, response, updateManager, callback){
12322         el.update(response.responseText, updateManager.loadScripts, callback);
12323     }
12324 };
12325 /*
12326  * Based on:
12327  * Roo JS
12328  * (c)) Alan Knowles
12329  * Licence : LGPL
12330  */
12331
12332
12333 /**
12334  * @class Roo.DomTemplate
12335  * @extends Roo.Template
12336  * An effort at a dom based template engine..
12337  *
12338  * Similar to XTemplate, except it uses dom parsing to create the template..
12339  *
12340  * Supported features:
12341  *
12342  *  Tags:
12343
12344 <pre><code>
12345       {a_variable} - output encoded.
12346       {a_variable.format:("Y-m-d")} - call a method on the variable
12347       {a_variable:raw} - unencoded output
12348       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12349       {a_variable:this.method_on_template(...)} - call a method on the template object.
12350  
12351 </code></pre>
12352  *  The tpl tag:
12353 <pre><code>
12354         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12355         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12356         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12357         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12358   
12359 </code></pre>
12360  *      
12361  */
12362 Roo.DomTemplate = function()
12363 {
12364      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12365      if (this.html) {
12366         this.compile();
12367      }
12368 };
12369
12370
12371 Roo.extend(Roo.DomTemplate, Roo.Template, {
12372     /**
12373      * id counter for sub templates.
12374      */
12375     id : 0,
12376     /**
12377      * flag to indicate if dom parser is inside a pre,
12378      * it will strip whitespace if not.
12379      */
12380     inPre : false,
12381     
12382     /**
12383      * The various sub templates
12384      */
12385     tpls : false,
12386     
12387     
12388     
12389     /**
12390      *
12391      * basic tag replacing syntax
12392      * WORD:WORD()
12393      *
12394      * // you can fake an object call by doing this
12395      *  x.t:(test,tesT) 
12396      * 
12397      */
12398     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12399     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12400     
12401     iterChild : function (node, method) {
12402         
12403         var oldPre = this.inPre;
12404         if (node.tagName == 'PRE') {
12405             this.inPre = true;
12406         }
12407         for( var i = 0; i < node.childNodes.length; i++) {
12408             method.call(this, node.childNodes[i]);
12409         }
12410         this.inPre = oldPre;
12411     },
12412     
12413     
12414     
12415     /**
12416      * compile the template
12417      *
12418      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12419      *
12420      */
12421     compile: function()
12422     {
12423         var s = this.html;
12424         
12425         // covert the html into DOM...
12426         var doc = false;
12427         var div =false;
12428         try {
12429             doc = document.implementation.createHTMLDocument("");
12430             doc.documentElement.innerHTML =   this.html  ;
12431             div = doc.documentElement;
12432         } catch (e) {
12433             // old IE... - nasty -- it causes all sorts of issues.. with
12434             // images getting pulled from server..
12435             div = document.createElement('div');
12436             div.innerHTML = this.html;
12437         }
12438         //doc.documentElement.innerHTML = htmlBody
12439          
12440         
12441         
12442         this.tpls = [];
12443         var _t = this;
12444         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12445         
12446         var tpls = this.tpls;
12447         
12448         // create a top level template from the snippet..
12449         
12450         //Roo.log(div.innerHTML);
12451         
12452         var tpl = {
12453             uid : 'master',
12454             id : this.id++,
12455             attr : false,
12456             value : false,
12457             body : div.innerHTML,
12458             
12459             forCall : false,
12460             execCall : false,
12461             dom : div,
12462             isTop : true
12463             
12464         };
12465         tpls.unshift(tpl);
12466         
12467         
12468         // compile them...
12469         this.tpls = [];
12470         Roo.each(tpls, function(tp){
12471             this.compileTpl(tp);
12472             this.tpls[tp.id] = tp;
12473         }, this);
12474         
12475         this.master = tpls[0];
12476         return this;
12477         
12478         
12479     },
12480     
12481     compileNode : function(node, istop) {
12482         // test for
12483         //Roo.log(node);
12484         
12485         
12486         // skip anything not a tag..
12487         if (node.nodeType != 1) {
12488             if (node.nodeType == 3 && !this.inPre) {
12489                 // reduce white space..
12490                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12491                 
12492             }
12493             return;
12494         }
12495         
12496         var tpl = {
12497             uid : false,
12498             id : false,
12499             attr : false,
12500             value : false,
12501             body : '',
12502             
12503             forCall : false,
12504             execCall : false,
12505             dom : false,
12506             isTop : istop
12507             
12508             
12509         };
12510         
12511         
12512         switch(true) {
12513             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12514             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12515             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12516             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12517             // no default..
12518         }
12519         
12520         
12521         if (!tpl.attr) {
12522             // just itterate children..
12523             this.iterChild(node,this.compileNode);
12524             return;
12525         }
12526         tpl.uid = this.id++;
12527         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12528         node.removeAttribute('roo-'+ tpl.attr);
12529         if (tpl.attr != 'name') {
12530             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12531             node.parentNode.replaceChild(placeholder,  node);
12532         } else {
12533             
12534             var placeholder =  document.createElement('span');
12535             placeholder.className = 'roo-tpl-' + tpl.value;
12536             node.parentNode.replaceChild(placeholder,  node);
12537         }
12538         
12539         // parent now sees '{domtplXXXX}
12540         this.iterChild(node,this.compileNode);
12541         
12542         // we should now have node body...
12543         var div = document.createElement('div');
12544         div.appendChild(node);
12545         tpl.dom = node;
12546         // this has the unfortunate side effect of converting tagged attributes
12547         // eg. href="{...}" into %7C...%7D
12548         // this has been fixed by searching for those combo's although it's a bit hacky..
12549         
12550         
12551         tpl.body = div.innerHTML;
12552         
12553         
12554          
12555         tpl.id = tpl.uid;
12556         switch(tpl.attr) {
12557             case 'for' :
12558                 switch (tpl.value) {
12559                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12560                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12561                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12562                 }
12563                 break;
12564             
12565             case 'exec':
12566                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12567                 break;
12568             
12569             case 'if':     
12570                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12571                 break;
12572             
12573             case 'name':
12574                 tpl.id  = tpl.value; // replace non characters???
12575                 break;
12576             
12577         }
12578         
12579         
12580         this.tpls.push(tpl);
12581         
12582         
12583         
12584     },
12585     
12586     
12587     
12588     
12589     /**
12590      * Compile a segment of the template into a 'sub-template'
12591      *
12592      * 
12593      * 
12594      *
12595      */
12596     compileTpl : function(tpl)
12597     {
12598         var fm = Roo.util.Format;
12599         var useF = this.disableFormats !== true;
12600         
12601         var sep = Roo.isGecko ? "+\n" : ",\n";
12602         
12603         var undef = function(str) {
12604             Roo.debug && Roo.log("Property not found :"  + str);
12605             return '';
12606         };
12607           
12608         //Roo.log(tpl.body);
12609         
12610         
12611         
12612         var fn = function(m, lbrace, name, format, args)
12613         {
12614             //Roo.log("ARGS");
12615             //Roo.log(arguments);
12616             args = args ? args.replace(/\\'/g,"'") : args;
12617             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12618             if (typeof(format) == 'undefined') {
12619                 format =  'htmlEncode'; 
12620             }
12621             if (format == 'raw' ) {
12622                 format = false;
12623             }
12624             
12625             if(name.substr(0, 6) == 'domtpl'){
12626                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12627             }
12628             
12629             // build an array of options to determine if value is undefined..
12630             
12631             // basically get 'xxxx.yyyy' then do
12632             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12633             //    (function () { Roo.log("Property not found"); return ''; })() :
12634             //    ......
12635             
12636             var udef_ar = [];
12637             var lookfor = '';
12638             Roo.each(name.split('.'), function(st) {
12639                 lookfor += (lookfor.length ? '.': '') + st;
12640                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12641             });
12642             
12643             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12644             
12645             
12646             if(format && useF){
12647                 
12648                 args = args ? ',' + args : "";
12649                  
12650                 if(format.substr(0, 5) != "this."){
12651                     format = "fm." + format + '(';
12652                 }else{
12653                     format = 'this.call("'+ format.substr(5) + '", ';
12654                     args = ", values";
12655                 }
12656                 
12657                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12658             }
12659              
12660             if (args && args.length) {
12661                 // called with xxyx.yuu:(test,test)
12662                 // change to ()
12663                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12664             }
12665             // raw.. - :raw modifier..
12666             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12667             
12668         };
12669         var body;
12670         // branched to use + in gecko and [].join() in others
12671         if(Roo.isGecko){
12672             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12673                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12674                     "';};};";
12675         }else{
12676             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12677             body.push(tpl.body.replace(/(\r\n|\n)/g,
12678                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12679             body.push("'].join('');};};");
12680             body = body.join('');
12681         }
12682         
12683         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12684        
12685         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12686         eval(body);
12687         
12688         return this;
12689     },
12690      
12691     /**
12692      * same as applyTemplate, except it's done to one of the subTemplates
12693      * when using named templates, you can do:
12694      *
12695      * var str = pl.applySubTemplate('your-name', values);
12696      *
12697      * 
12698      * @param {Number} id of the template
12699      * @param {Object} values to apply to template
12700      * @param {Object} parent (normaly the instance of this object)
12701      */
12702     applySubTemplate : function(id, values, parent)
12703     {
12704         
12705         
12706         var t = this.tpls[id];
12707         
12708         
12709         try { 
12710             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12711                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12712                 return '';
12713             }
12714         } catch(e) {
12715             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12716             Roo.log(values);
12717           
12718             return '';
12719         }
12720         try { 
12721             
12722             if(t.execCall && t.execCall.call(this, values, parent)){
12723                 return '';
12724             }
12725         } catch(e) {
12726             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12727             Roo.log(values);
12728             return '';
12729         }
12730         
12731         try {
12732             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12733             parent = t.target ? values : parent;
12734             if(t.forCall && vs instanceof Array){
12735                 var buf = [];
12736                 for(var i = 0, len = vs.length; i < len; i++){
12737                     try {
12738                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12739                     } catch (e) {
12740                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12741                         Roo.log(e.body);
12742                         //Roo.log(t.compiled);
12743                         Roo.log(vs[i]);
12744                     }   
12745                 }
12746                 return buf.join('');
12747             }
12748         } catch (e) {
12749             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12750             Roo.log(values);
12751             return '';
12752         }
12753         try {
12754             return t.compiled.call(this, vs, parent);
12755         } catch (e) {
12756             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12757             Roo.log(e.body);
12758             //Roo.log(t.compiled);
12759             Roo.log(values);
12760             return '';
12761         }
12762     },
12763
12764    
12765
12766     applyTemplate : function(values){
12767         return this.master.compiled.call(this, values, {});
12768         //var s = this.subs;
12769     },
12770
12771     apply : function(){
12772         return this.applyTemplate.apply(this, arguments);
12773     }
12774
12775  });
12776
12777 Roo.DomTemplate.from = function(el){
12778     el = Roo.getDom(el);
12779     return new Roo.Domtemplate(el.value || el.innerHTML);
12780 };/*
12781  * Based on:
12782  * Ext JS Library 1.1.1
12783  * Copyright(c) 2006-2007, Ext JS, LLC.
12784  *
12785  * Originally Released Under LGPL - original licence link has changed is not relivant.
12786  *
12787  * Fork - LGPL
12788  * <script type="text/javascript">
12789  */
12790
12791 /**
12792  * @class Roo.util.DelayedTask
12793  * Provides a convenient method of performing setTimeout where a new
12794  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12795  * You can use this class to buffer
12796  * the keypress events for a certain number of milliseconds, and perform only if they stop
12797  * for that amount of time.
12798  * @constructor The parameters to this constructor serve as defaults and are not required.
12799  * @param {Function} fn (optional) The default function to timeout
12800  * @param {Object} scope (optional) The default scope of that timeout
12801  * @param {Array} args (optional) The default Array of arguments
12802  */
12803 Roo.util.DelayedTask = function(fn, scope, args){
12804     var id = null, d, t;
12805
12806     var call = function(){
12807         var now = new Date().getTime();
12808         if(now - t >= d){
12809             clearInterval(id);
12810             id = null;
12811             fn.apply(scope, args || []);
12812         }
12813     };
12814     /**
12815      * Cancels any pending timeout and queues a new one
12816      * @param {Number} delay The milliseconds to delay
12817      * @param {Function} newFn (optional) Overrides function passed to constructor
12818      * @param {Object} newScope (optional) Overrides scope passed to constructor
12819      * @param {Array} newArgs (optional) Overrides args passed to constructor
12820      */
12821     this.delay = function(delay, newFn, newScope, newArgs){
12822         if(id && delay != d){
12823             this.cancel();
12824         }
12825         d = delay;
12826         t = new Date().getTime();
12827         fn = newFn || fn;
12828         scope = newScope || scope;
12829         args = newArgs || args;
12830         if(!id){
12831             id = setInterval(call, d);
12832         }
12833     };
12834
12835     /**
12836      * Cancel the last queued timeout
12837      */
12838     this.cancel = function(){
12839         if(id){
12840             clearInterval(id);
12841             id = null;
12842         }
12843     };
12844 };/*
12845  * Based on:
12846  * Ext JS Library 1.1.1
12847  * Copyright(c) 2006-2007, Ext JS, LLC.
12848  *
12849  * Originally Released Under LGPL - original licence link has changed is not relivant.
12850  *
12851  * Fork - LGPL
12852  * <script type="text/javascript">
12853  */
12854  
12855  
12856 Roo.util.TaskRunner = function(interval){
12857     interval = interval || 10;
12858     var tasks = [], removeQueue = [];
12859     var id = 0;
12860     var running = false;
12861
12862     var stopThread = function(){
12863         running = false;
12864         clearInterval(id);
12865         id = 0;
12866     };
12867
12868     var startThread = function(){
12869         if(!running){
12870             running = true;
12871             id = setInterval(runTasks, interval);
12872         }
12873     };
12874
12875     var removeTask = function(task){
12876         removeQueue.push(task);
12877         if(task.onStop){
12878             task.onStop();
12879         }
12880     };
12881
12882     var runTasks = function(){
12883         if(removeQueue.length > 0){
12884             for(var i = 0, len = removeQueue.length; i < len; i++){
12885                 tasks.remove(removeQueue[i]);
12886             }
12887             removeQueue = [];
12888             if(tasks.length < 1){
12889                 stopThread();
12890                 return;
12891             }
12892         }
12893         var now = new Date().getTime();
12894         for(var i = 0, len = tasks.length; i < len; ++i){
12895             var t = tasks[i];
12896             var itime = now - t.taskRunTime;
12897             if(t.interval <= itime){
12898                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12899                 t.taskRunTime = now;
12900                 if(rt === false || t.taskRunCount === t.repeat){
12901                     removeTask(t);
12902                     return;
12903                 }
12904             }
12905             if(t.duration && t.duration <= (now - t.taskStartTime)){
12906                 removeTask(t);
12907             }
12908         }
12909     };
12910
12911     /**
12912      * Queues a new task.
12913      * @param {Object} task
12914      */
12915     this.start = function(task){
12916         tasks.push(task);
12917         task.taskStartTime = new Date().getTime();
12918         task.taskRunTime = 0;
12919         task.taskRunCount = 0;
12920         startThread();
12921         return task;
12922     };
12923
12924     this.stop = function(task){
12925         removeTask(task);
12926         return task;
12927     };
12928
12929     this.stopAll = function(){
12930         stopThread();
12931         for(var i = 0, len = tasks.length; i < len; i++){
12932             if(tasks[i].onStop){
12933                 tasks[i].onStop();
12934             }
12935         }
12936         tasks = [];
12937         removeQueue = [];
12938     };
12939 };
12940
12941 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12942  * Based on:
12943  * Ext JS Library 1.1.1
12944  * Copyright(c) 2006-2007, Ext JS, LLC.
12945  *
12946  * Originally Released Under LGPL - original licence link has changed is not relivant.
12947  *
12948  * Fork - LGPL
12949  * <script type="text/javascript">
12950  */
12951
12952  
12953 /**
12954  * @class Roo.util.MixedCollection
12955  * @extends Roo.util.Observable
12956  * A Collection class that maintains both numeric indexes and keys and exposes events.
12957  * @constructor
12958  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12959  * collection (defaults to false)
12960  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12961  * and return the key value for that item.  This is used when available to look up the key on items that
12962  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12963  * equivalent to providing an implementation for the {@link #getKey} method.
12964  */
12965 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12966     this.items = [];
12967     this.map = {};
12968     this.keys = [];
12969     this.length = 0;
12970     this.addEvents({
12971         /**
12972          * @event clear
12973          * Fires when the collection is cleared.
12974          */
12975         "clear" : true,
12976         /**
12977          * @event add
12978          * Fires when an item is added to the collection.
12979          * @param {Number} index The index at which the item was added.
12980          * @param {Object} o The item added.
12981          * @param {String} key The key associated with the added item.
12982          */
12983         "add" : true,
12984         /**
12985          * @event replace
12986          * Fires when an item is replaced in the collection.
12987          * @param {String} key he key associated with the new added.
12988          * @param {Object} old The item being replaced.
12989          * @param {Object} new The new item.
12990          */
12991         "replace" : true,
12992         /**
12993          * @event remove
12994          * Fires when an item is removed from the collection.
12995          * @param {Object} o The item being removed.
12996          * @param {String} key (optional) The key associated with the removed item.
12997          */
12998         "remove" : true,
12999         "sort" : true
13000     });
13001     this.allowFunctions = allowFunctions === true;
13002     if(keyFn){
13003         this.getKey = keyFn;
13004     }
13005     Roo.util.MixedCollection.superclass.constructor.call(this);
13006 };
13007
13008 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13009     allowFunctions : false,
13010     
13011 /**
13012  * Adds an item to the collection.
13013  * @param {String} key The key to associate with the item
13014  * @param {Object} o The item to add.
13015  * @return {Object} The item added.
13016  */
13017     add : function(key, o){
13018         if(arguments.length == 1){
13019             o = arguments[0];
13020             key = this.getKey(o);
13021         }
13022         if(typeof key == "undefined" || key === null){
13023             this.length++;
13024             this.items.push(o);
13025             this.keys.push(null);
13026         }else{
13027             var old = this.map[key];
13028             if(old){
13029                 return this.replace(key, o);
13030             }
13031             this.length++;
13032             this.items.push(o);
13033             this.map[key] = o;
13034             this.keys.push(key);
13035         }
13036         this.fireEvent("add", this.length-1, o, key);
13037         return o;
13038     },
13039        
13040 /**
13041   * MixedCollection has a generic way to fetch keys if you implement getKey.
13042 <pre><code>
13043 // normal way
13044 var mc = new Roo.util.MixedCollection();
13045 mc.add(someEl.dom.id, someEl);
13046 mc.add(otherEl.dom.id, otherEl);
13047 //and so on
13048
13049 // using getKey
13050 var mc = new Roo.util.MixedCollection();
13051 mc.getKey = function(el){
13052    return el.dom.id;
13053 };
13054 mc.add(someEl);
13055 mc.add(otherEl);
13056
13057 // or via the constructor
13058 var mc = new Roo.util.MixedCollection(false, function(el){
13059    return el.dom.id;
13060 });
13061 mc.add(someEl);
13062 mc.add(otherEl);
13063 </code></pre>
13064  * @param o {Object} The item for which to find the key.
13065  * @return {Object} The key for the passed item.
13066  */
13067     getKey : function(o){
13068          return o.id; 
13069     },
13070    
13071 /**
13072  * Replaces an item in the collection.
13073  * @param {String} key The key associated with the item to replace, or the item to replace.
13074  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13075  * @return {Object}  The new item.
13076  */
13077     replace : function(key, o){
13078         if(arguments.length == 1){
13079             o = arguments[0];
13080             key = this.getKey(o);
13081         }
13082         var old = this.item(key);
13083         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13084              return this.add(key, o);
13085         }
13086         var index = this.indexOfKey(key);
13087         this.items[index] = o;
13088         this.map[key] = o;
13089         this.fireEvent("replace", key, old, o);
13090         return o;
13091     },
13092    
13093 /**
13094  * Adds all elements of an Array or an Object to the collection.
13095  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13096  * an Array of values, each of which are added to the collection.
13097  */
13098     addAll : function(objs){
13099         if(arguments.length > 1 || objs instanceof Array){
13100             var args = arguments.length > 1 ? arguments : objs;
13101             for(var i = 0, len = args.length; i < len; i++){
13102                 this.add(args[i]);
13103             }
13104         }else{
13105             for(var key in objs){
13106                 if(this.allowFunctions || typeof objs[key] != "function"){
13107                     this.add(key, objs[key]);
13108                 }
13109             }
13110         }
13111     },
13112    
13113 /**
13114  * Executes the specified function once for every item in the collection, passing each
13115  * item as the first and only parameter. returning false from the function will stop the iteration.
13116  * @param {Function} fn The function to execute for each item.
13117  * @param {Object} scope (optional) The scope in which to execute the function.
13118  */
13119     each : function(fn, scope){
13120         var items = [].concat(this.items); // each safe for removal
13121         for(var i = 0, len = items.length; i < len; i++){
13122             if(fn.call(scope || items[i], items[i], i, len) === false){
13123                 break;
13124             }
13125         }
13126     },
13127    
13128 /**
13129  * Executes the specified function once for every key in the collection, passing each
13130  * key, and its associated item as the first two parameters.
13131  * @param {Function} fn The function to execute for each item.
13132  * @param {Object} scope (optional) The scope in which to execute the function.
13133  */
13134     eachKey : function(fn, scope){
13135         for(var i = 0, len = this.keys.length; i < len; i++){
13136             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13137         }
13138     },
13139    
13140 /**
13141  * Returns the first item in the collection which elicits a true return value from the
13142  * passed selection function.
13143  * @param {Function} fn The selection function to execute for each item.
13144  * @param {Object} scope (optional) The scope in which to execute the function.
13145  * @return {Object} The first item in the collection which returned true from the selection function.
13146  */
13147     find : function(fn, scope){
13148         for(var i = 0, len = this.items.length; i < len; i++){
13149             if(fn.call(scope || window, this.items[i], this.keys[i])){
13150                 return this.items[i];
13151             }
13152         }
13153         return null;
13154     },
13155    
13156 /**
13157  * Inserts an item at the specified index in the collection.
13158  * @param {Number} index The index to insert the item at.
13159  * @param {String} key The key to associate with the new item, or the item itself.
13160  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13161  * @return {Object} The item inserted.
13162  */
13163     insert : function(index, key, o){
13164         if(arguments.length == 2){
13165             o = arguments[1];
13166             key = this.getKey(o);
13167         }
13168         if(index >= this.length){
13169             return this.add(key, o);
13170         }
13171         this.length++;
13172         this.items.splice(index, 0, o);
13173         if(typeof key != "undefined" && key != null){
13174             this.map[key] = o;
13175         }
13176         this.keys.splice(index, 0, key);
13177         this.fireEvent("add", index, o, key);
13178         return o;
13179     },
13180    
13181 /**
13182  * Removed an item from the collection.
13183  * @param {Object} o The item to remove.
13184  * @return {Object} The item removed.
13185  */
13186     remove : function(o){
13187         return this.removeAt(this.indexOf(o));
13188     },
13189    
13190 /**
13191  * Remove an item from a specified index in the collection.
13192  * @param {Number} index The index within the collection of the item to remove.
13193  */
13194     removeAt : function(index){
13195         if(index < this.length && index >= 0){
13196             this.length--;
13197             var o = this.items[index];
13198             this.items.splice(index, 1);
13199             var key = this.keys[index];
13200             if(typeof key != "undefined"){
13201                 delete this.map[key];
13202             }
13203             this.keys.splice(index, 1);
13204             this.fireEvent("remove", o, key);
13205         }
13206     },
13207    
13208 /**
13209  * Removed an item associated with the passed key fom the collection.
13210  * @param {String} key The key of the item to remove.
13211  */
13212     removeKey : function(key){
13213         return this.removeAt(this.indexOfKey(key));
13214     },
13215    
13216 /**
13217  * Returns the number of items in the collection.
13218  * @return {Number} the number of items in the collection.
13219  */
13220     getCount : function(){
13221         return this.length; 
13222     },
13223    
13224 /**
13225  * Returns index within the collection of the passed Object.
13226  * @param {Object} o The item to find the index of.
13227  * @return {Number} index of the item.
13228  */
13229     indexOf : function(o){
13230         if(!this.items.indexOf){
13231             for(var i = 0, len = this.items.length; i < len; i++){
13232                 if(this.items[i] == o) {
13233                     return i;
13234                 }
13235             }
13236             return -1;
13237         }else{
13238             return this.items.indexOf(o);
13239         }
13240     },
13241    
13242 /**
13243  * Returns index within the collection of the passed key.
13244  * @param {String} key The key to find the index of.
13245  * @return {Number} index of the key.
13246  */
13247     indexOfKey : function(key){
13248         if(!this.keys.indexOf){
13249             for(var i = 0, len = this.keys.length; i < len; i++){
13250                 if(this.keys[i] == key) {
13251                     return i;
13252                 }
13253             }
13254             return -1;
13255         }else{
13256             return this.keys.indexOf(key);
13257         }
13258     },
13259    
13260 /**
13261  * Returns the item associated with the passed key OR index. Key has priority over index.
13262  * @param {String/Number} key The key or index of the item.
13263  * @return {Object} The item associated with the passed key.
13264  */
13265     item : function(key){
13266         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13267         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13268     },
13269     
13270 /**
13271  * Returns the item at the specified index.
13272  * @param {Number} index The index of the item.
13273  * @return {Object}
13274  */
13275     itemAt : function(index){
13276         return this.items[index];
13277     },
13278     
13279 /**
13280  * Returns the item associated with the passed key.
13281  * @param {String/Number} key The key of the item.
13282  * @return {Object} The item associated with the passed key.
13283  */
13284     key : function(key){
13285         return this.map[key];
13286     },
13287    
13288 /**
13289  * Returns true if the collection contains the passed Object as an item.
13290  * @param {Object} o  The Object to look for in the collection.
13291  * @return {Boolean} True if the collection contains the Object as an item.
13292  */
13293     contains : function(o){
13294         return this.indexOf(o) != -1;
13295     },
13296    
13297 /**
13298  * Returns true if the collection contains the passed Object as a key.
13299  * @param {String} key The key to look for in the collection.
13300  * @return {Boolean} True if the collection contains the Object as a key.
13301  */
13302     containsKey : function(key){
13303         return typeof this.map[key] != "undefined";
13304     },
13305    
13306 /**
13307  * Removes all items from the collection.
13308  */
13309     clear : function(){
13310         this.length = 0;
13311         this.items = [];
13312         this.keys = [];
13313         this.map = {};
13314         this.fireEvent("clear");
13315     },
13316    
13317 /**
13318  * Returns the first item in the collection.
13319  * @return {Object} the first item in the collection..
13320  */
13321     first : function(){
13322         return this.items[0]; 
13323     },
13324    
13325 /**
13326  * Returns the last item in the collection.
13327  * @return {Object} the last item in the collection..
13328  */
13329     last : function(){
13330         return this.items[this.length-1];   
13331     },
13332     
13333     _sort : function(property, dir, fn){
13334         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13335         fn = fn || function(a, b){
13336             return a-b;
13337         };
13338         var c = [], k = this.keys, items = this.items;
13339         for(var i = 0, len = items.length; i < len; i++){
13340             c[c.length] = {key: k[i], value: items[i], index: i};
13341         }
13342         c.sort(function(a, b){
13343             var v = fn(a[property], b[property]) * dsc;
13344             if(v == 0){
13345                 v = (a.index < b.index ? -1 : 1);
13346             }
13347             return v;
13348         });
13349         for(var i = 0, len = c.length; i < len; i++){
13350             items[i] = c[i].value;
13351             k[i] = c[i].key;
13352         }
13353         this.fireEvent("sort", this);
13354     },
13355     
13356     /**
13357      * Sorts this collection with the passed comparison function
13358      * @param {String} direction (optional) "ASC" or "DESC"
13359      * @param {Function} fn (optional) comparison function
13360      */
13361     sort : function(dir, fn){
13362         this._sort("value", dir, fn);
13363     },
13364     
13365     /**
13366      * Sorts this collection by keys
13367      * @param {String} direction (optional) "ASC" or "DESC"
13368      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13369      */
13370     keySort : function(dir, fn){
13371         this._sort("key", dir, fn || function(a, b){
13372             return String(a).toUpperCase()-String(b).toUpperCase();
13373         });
13374     },
13375     
13376     /**
13377      * Returns a range of items in this collection
13378      * @param {Number} startIndex (optional) defaults to 0
13379      * @param {Number} endIndex (optional) default to the last item
13380      * @return {Array} An array of items
13381      */
13382     getRange : function(start, end){
13383         var items = this.items;
13384         if(items.length < 1){
13385             return [];
13386         }
13387         start = start || 0;
13388         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13389         var r = [];
13390         if(start <= end){
13391             for(var i = start; i <= end; i++) {
13392                     r[r.length] = items[i];
13393             }
13394         }else{
13395             for(var i = start; i >= end; i--) {
13396                     r[r.length] = items[i];
13397             }
13398         }
13399         return r;
13400     },
13401         
13402     /**
13403      * Filter the <i>objects</i> in this collection by a specific property. 
13404      * Returns a new collection that has been filtered.
13405      * @param {String} property A property on your objects
13406      * @param {String/RegExp} value Either string that the property values 
13407      * should start with or a RegExp to test against the property
13408      * @return {MixedCollection} The new filtered collection
13409      */
13410     filter : function(property, value){
13411         if(!value.exec){ // not a regex
13412             value = String(value);
13413             if(value.length == 0){
13414                 return this.clone();
13415             }
13416             value = new RegExp("^" + Roo.escapeRe(value), "i");
13417         }
13418         return this.filterBy(function(o){
13419             return o && value.test(o[property]);
13420         });
13421         },
13422     
13423     /**
13424      * Filter by a function. * Returns a new collection that has been filtered.
13425      * The passed function will be called with each 
13426      * object in the collection. If the function returns true, the value is included 
13427      * otherwise it is filtered.
13428      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13429      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13430      * @return {MixedCollection} The new filtered collection
13431      */
13432     filterBy : function(fn, scope){
13433         var r = new Roo.util.MixedCollection();
13434         r.getKey = this.getKey;
13435         var k = this.keys, it = this.items;
13436         for(var i = 0, len = it.length; i < len; i++){
13437             if(fn.call(scope||this, it[i], k[i])){
13438                                 r.add(k[i], it[i]);
13439                         }
13440         }
13441         return r;
13442     },
13443     
13444     /**
13445      * Creates a duplicate of this collection
13446      * @return {MixedCollection}
13447      */
13448     clone : function(){
13449         var r = new Roo.util.MixedCollection();
13450         var k = this.keys, it = this.items;
13451         for(var i = 0, len = it.length; i < len; i++){
13452             r.add(k[i], it[i]);
13453         }
13454         r.getKey = this.getKey;
13455         return r;
13456     }
13457 });
13458 /**
13459  * Returns the item associated with the passed key or index.
13460  * @method
13461  * @param {String/Number} key The key or index of the item.
13462  * @return {Object} The item associated with the passed key.
13463  */
13464 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13465  * Based on:
13466  * Ext JS Library 1.1.1
13467  * Copyright(c) 2006-2007, Ext JS, LLC.
13468  *
13469  * Originally Released Under LGPL - original licence link has changed is not relivant.
13470  *
13471  * Fork - LGPL
13472  * <script type="text/javascript">
13473  */
13474 /**
13475  * @class Roo.util.JSON
13476  * Modified version of Douglas Crockford"s json.js that doesn"t
13477  * mess with the Object prototype 
13478  * http://www.json.org/js.html
13479  * @singleton
13480  */
13481 Roo.util.JSON = new (function(){
13482     var useHasOwn = {}.hasOwnProperty ? true : false;
13483     
13484     // crashes Safari in some instances
13485     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13486     
13487     var pad = function(n) {
13488         return n < 10 ? "0" + n : n;
13489     };
13490     
13491     var m = {
13492         "\b": '\\b',
13493         "\t": '\\t',
13494         "\n": '\\n',
13495         "\f": '\\f',
13496         "\r": '\\r',
13497         '"' : '\\"',
13498         "\\": '\\\\'
13499     };
13500
13501     var encodeString = function(s){
13502         if (/["\\\x00-\x1f]/.test(s)) {
13503             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13504                 var c = m[b];
13505                 if(c){
13506                     return c;
13507                 }
13508                 c = b.charCodeAt();
13509                 return "\\u00" +
13510                     Math.floor(c / 16).toString(16) +
13511                     (c % 16).toString(16);
13512             }) + '"';
13513         }
13514         return '"' + s + '"';
13515     };
13516     
13517     var encodeArray = function(o){
13518         var a = ["["], b, i, l = o.length, v;
13519             for (i = 0; i < l; i += 1) {
13520                 v = o[i];
13521                 switch (typeof v) {
13522                     case "undefined":
13523                     case "function":
13524                     case "unknown":
13525                         break;
13526                     default:
13527                         if (b) {
13528                             a.push(',');
13529                         }
13530                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13531                         b = true;
13532                 }
13533             }
13534             a.push("]");
13535             return a.join("");
13536     };
13537     
13538     var encodeDate = function(o){
13539         return '"' + o.getFullYear() + "-" +
13540                 pad(o.getMonth() + 1) + "-" +
13541                 pad(o.getDate()) + "T" +
13542                 pad(o.getHours()) + ":" +
13543                 pad(o.getMinutes()) + ":" +
13544                 pad(o.getSeconds()) + '"';
13545     };
13546     
13547     /**
13548      * Encodes an Object, Array or other value
13549      * @param {Mixed} o The variable to encode
13550      * @return {String} The JSON string
13551      */
13552     this.encode = function(o)
13553     {
13554         // should this be extended to fully wrap stringify..
13555         
13556         if(typeof o == "undefined" || o === null){
13557             return "null";
13558         }else if(o instanceof Array){
13559             return encodeArray(o);
13560         }else if(o instanceof Date){
13561             return encodeDate(o);
13562         }else if(typeof o == "string"){
13563             return encodeString(o);
13564         }else if(typeof o == "number"){
13565             return isFinite(o) ? String(o) : "null";
13566         }else if(typeof o == "boolean"){
13567             return String(o);
13568         }else {
13569             var a = ["{"], b, i, v;
13570             for (i in o) {
13571                 if(!useHasOwn || o.hasOwnProperty(i)) {
13572                     v = o[i];
13573                     switch (typeof v) {
13574                     case "undefined":
13575                     case "function":
13576                     case "unknown":
13577                         break;
13578                     default:
13579                         if(b){
13580                             a.push(',');
13581                         }
13582                         a.push(this.encode(i), ":",
13583                                 v === null ? "null" : this.encode(v));
13584                         b = true;
13585                     }
13586                 }
13587             }
13588             a.push("}");
13589             return a.join("");
13590         }
13591     };
13592     
13593     /**
13594      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13595      * @param {String} json The JSON string
13596      * @return {Object} The resulting object
13597      */
13598     this.decode = function(json){
13599         
13600         return  /** eval:var:json */ eval("(" + json + ')');
13601     };
13602 })();
13603 /** 
13604  * Shorthand for {@link Roo.util.JSON#encode}
13605  * @member Roo encode 
13606  * @method */
13607 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13608 /** 
13609  * Shorthand for {@link Roo.util.JSON#decode}
13610  * @member Roo decode 
13611  * @method */
13612 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13613 /*
13614  * Based on:
13615  * Ext JS Library 1.1.1
13616  * Copyright(c) 2006-2007, Ext JS, LLC.
13617  *
13618  * Originally Released Under LGPL - original licence link has changed is not relivant.
13619  *
13620  * Fork - LGPL
13621  * <script type="text/javascript">
13622  */
13623  
13624 /**
13625  * @class Roo.util.Format
13626  * Reusable data formatting functions
13627  * @singleton
13628  */
13629 Roo.util.Format = function(){
13630     var trimRe = /^\s+|\s+$/g;
13631     return {
13632         /**
13633          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13634          * @param {String} value The string to truncate
13635          * @param {Number} length The maximum length to allow before truncating
13636          * @return {String} The converted text
13637          */
13638         ellipsis : function(value, len){
13639             if(value && value.length > len){
13640                 return value.substr(0, len-3)+"...";
13641             }
13642             return value;
13643         },
13644
13645         /**
13646          * Checks a reference and converts it to empty string if it is undefined
13647          * @param {Mixed} value Reference to check
13648          * @return {Mixed} Empty string if converted, otherwise the original value
13649          */
13650         undef : function(value){
13651             return typeof value != "undefined" ? value : "";
13652         },
13653
13654         /**
13655          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13656          * @param {String} value The string to encode
13657          * @return {String} The encoded text
13658          */
13659         htmlEncode : function(value){
13660             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13661         },
13662
13663         /**
13664          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13665          * @param {String} value The string to decode
13666          * @return {String} The decoded text
13667          */
13668         htmlDecode : function(value){
13669             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13670         },
13671
13672         /**
13673          * Trims any whitespace from either side of a string
13674          * @param {String} value The text to trim
13675          * @return {String} The trimmed text
13676          */
13677         trim : function(value){
13678             return String(value).replace(trimRe, "");
13679         },
13680
13681         /**
13682          * Returns a substring from within an original string
13683          * @param {String} value The original text
13684          * @param {Number} start The start index of the substring
13685          * @param {Number} length The length of the substring
13686          * @return {String} The substring
13687          */
13688         substr : function(value, start, length){
13689             return String(value).substr(start, length);
13690         },
13691
13692         /**
13693          * Converts a string to all lower case letters
13694          * @param {String} value The text to convert
13695          * @return {String} The converted text
13696          */
13697         lowercase : function(value){
13698             return String(value).toLowerCase();
13699         },
13700
13701         /**
13702          * Converts a string to all upper case letters
13703          * @param {String} value The text to convert
13704          * @return {String} The converted text
13705          */
13706         uppercase : function(value){
13707             return String(value).toUpperCase();
13708         },
13709
13710         /**
13711          * Converts the first character only of a string to upper case
13712          * @param {String} value The text to convert
13713          * @return {String} The converted text
13714          */
13715         capitalize : function(value){
13716             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13717         },
13718
13719         // private
13720         call : function(value, fn){
13721             if(arguments.length > 2){
13722                 var args = Array.prototype.slice.call(arguments, 2);
13723                 args.unshift(value);
13724                  
13725                 return /** eval:var:value */  eval(fn).apply(window, args);
13726             }else{
13727                 /** eval:var:value */
13728                 return /** eval:var:value */ eval(fn).call(window, value);
13729             }
13730         },
13731
13732        
13733         /**
13734          * safer version of Math.toFixed..??/
13735          * @param {Number/String} value The numeric value to format
13736          * @param {Number/String} value Decimal places 
13737          * @return {String} The formatted currency string
13738          */
13739         toFixed : function(v, n)
13740         {
13741             // why not use to fixed - precision is buggered???
13742             if (!n) {
13743                 return Math.round(v-0);
13744             }
13745             var fact = Math.pow(10,n+1);
13746             v = (Math.round((v-0)*fact))/fact;
13747             var z = (''+fact).substring(2);
13748             if (v == Math.floor(v)) {
13749                 return Math.floor(v) + '.' + z;
13750             }
13751             
13752             // now just padd decimals..
13753             var ps = String(v).split('.');
13754             var fd = (ps[1] + z);
13755             var r = fd.substring(0,n); 
13756             var rm = fd.substring(n); 
13757             if (rm < 5) {
13758                 return ps[0] + '.' + r;
13759             }
13760             r*=1; // turn it into a number;
13761             r++;
13762             if (String(r).length != n) {
13763                 ps[0]*=1;
13764                 ps[0]++;
13765                 r = String(r).substring(1); // chop the end off.
13766             }
13767             
13768             return ps[0] + '.' + r;
13769              
13770         },
13771         
13772         /**
13773          * Format a number as US currency
13774          * @param {Number/String} value The numeric value to format
13775          * @return {String} The formatted currency string
13776          */
13777         usMoney : function(v){
13778             return '$' + Roo.util.Format.number(v);
13779         },
13780         
13781         /**
13782          * Format a number
13783          * eventually this should probably emulate php's number_format
13784          * @param {Number/String} value The numeric value to format
13785          * @param {Number} decimals number of decimal places
13786          * @param {String} delimiter for thousands (default comma)
13787          * @return {String} The formatted currency string
13788          */
13789         number : function(v, decimals, thousandsDelimiter)
13790         {
13791             // multiply and round.
13792             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13793             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13794             
13795             var mul = Math.pow(10, decimals);
13796             var zero = String(mul).substring(1);
13797             v = (Math.round((v-0)*mul))/mul;
13798             
13799             // if it's '0' number.. then
13800             
13801             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13802             v = String(v);
13803             var ps = v.split('.');
13804             var whole = ps[0];
13805             
13806             var r = /(\d+)(\d{3})/;
13807             // add comma's
13808             
13809             if(thousandsDelimiter.length != 0) {
13810                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13811             } 
13812             
13813             var sub = ps[1] ?
13814                     // has decimals..
13815                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13816                     // does not have decimals
13817                     (decimals ? ('.' + zero) : '');
13818             
13819             
13820             return whole + sub ;
13821         },
13822         
13823         /**
13824          * Parse a value into a formatted date using the specified format pattern.
13825          * @param {Mixed} value The value to format
13826          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13827          * @return {String} The formatted date string
13828          */
13829         date : function(v, format){
13830             if(!v){
13831                 return "";
13832             }
13833             if(!(v instanceof Date)){
13834                 v = new Date(Date.parse(v));
13835             }
13836             return v.dateFormat(format || Roo.util.Format.defaults.date);
13837         },
13838
13839         /**
13840          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13841          * @param {String} format Any valid date format string
13842          * @return {Function} The date formatting function
13843          */
13844         dateRenderer : function(format){
13845             return function(v){
13846                 return Roo.util.Format.date(v, format);  
13847             };
13848         },
13849
13850         // private
13851         stripTagsRE : /<\/?[^>]+>/gi,
13852         
13853         /**
13854          * Strips all HTML tags
13855          * @param {Mixed} value The text from which to strip tags
13856          * @return {String} The stripped text
13857          */
13858         stripTags : function(v){
13859             return !v ? v : String(v).replace(this.stripTagsRE, "");
13860         }
13861     };
13862 }();
13863 Roo.util.Format.defaults = {
13864     date : 'd/M/Y'
13865 };/*
13866  * Based on:
13867  * Ext JS Library 1.1.1
13868  * Copyright(c) 2006-2007, Ext JS, LLC.
13869  *
13870  * Originally Released Under LGPL - original licence link has changed is not relivant.
13871  *
13872  * Fork - LGPL
13873  * <script type="text/javascript">
13874  */
13875
13876
13877  
13878
13879 /**
13880  * @class Roo.MasterTemplate
13881  * @extends Roo.Template
13882  * Provides a template that can have child templates. The syntax is:
13883 <pre><code>
13884 var t = new Roo.MasterTemplate(
13885         '&lt;select name="{name}"&gt;',
13886                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13887         '&lt;/select&gt;'
13888 );
13889 t.add('options', {value: 'foo', text: 'bar'});
13890 // or you can add multiple child elements in one shot
13891 t.addAll('options', [
13892     {value: 'foo', text: 'bar'},
13893     {value: 'foo2', text: 'bar2'},
13894     {value: 'foo3', text: 'bar3'}
13895 ]);
13896 // then append, applying the master template values
13897 t.append('my-form', {name: 'my-select'});
13898 </code></pre>
13899 * A name attribute for the child template is not required if you have only one child
13900 * template or you want to refer to them by index.
13901  */
13902 Roo.MasterTemplate = function(){
13903     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13904     this.originalHtml = this.html;
13905     var st = {};
13906     var m, re = this.subTemplateRe;
13907     re.lastIndex = 0;
13908     var subIndex = 0;
13909     while(m = re.exec(this.html)){
13910         var name = m[1], content = m[2];
13911         st[subIndex] = {
13912             name: name,
13913             index: subIndex,
13914             buffer: [],
13915             tpl : new Roo.Template(content)
13916         };
13917         if(name){
13918             st[name] = st[subIndex];
13919         }
13920         st[subIndex].tpl.compile();
13921         st[subIndex].tpl.call = this.call.createDelegate(this);
13922         subIndex++;
13923     }
13924     this.subCount = subIndex;
13925     this.subs = st;
13926 };
13927 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13928     /**
13929     * The regular expression used to match sub templates
13930     * @type RegExp
13931     * @property
13932     */
13933     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13934
13935     /**
13936      * Applies the passed values to a child template.
13937      * @param {String/Number} name (optional) The name or index of the child template
13938      * @param {Array/Object} values The values to be applied to the template
13939      * @return {MasterTemplate} this
13940      */
13941      add : function(name, values){
13942         if(arguments.length == 1){
13943             values = arguments[0];
13944             name = 0;
13945         }
13946         var s = this.subs[name];
13947         s.buffer[s.buffer.length] = s.tpl.apply(values);
13948         return this;
13949     },
13950
13951     /**
13952      * Applies all the passed values to a child template.
13953      * @param {String/Number} name (optional) The name or index of the child template
13954      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13955      * @param {Boolean} reset (optional) True to reset the template first
13956      * @return {MasterTemplate} this
13957      */
13958     fill : function(name, values, reset){
13959         var a = arguments;
13960         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13961             values = a[0];
13962             name = 0;
13963             reset = a[1];
13964         }
13965         if(reset){
13966             this.reset();
13967         }
13968         for(var i = 0, len = values.length; i < len; i++){
13969             this.add(name, values[i]);
13970         }
13971         return this;
13972     },
13973
13974     /**
13975      * Resets the template for reuse
13976      * @return {MasterTemplate} this
13977      */
13978      reset : function(){
13979         var s = this.subs;
13980         for(var i = 0; i < this.subCount; i++){
13981             s[i].buffer = [];
13982         }
13983         return this;
13984     },
13985
13986     applyTemplate : function(values){
13987         var s = this.subs;
13988         var replaceIndex = -1;
13989         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13990             return s[++replaceIndex].buffer.join("");
13991         });
13992         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13993     },
13994
13995     apply : function(){
13996         return this.applyTemplate.apply(this, arguments);
13997     },
13998
13999     compile : function(){return this;}
14000 });
14001
14002 /**
14003  * Alias for fill().
14004  * @method
14005  */
14006 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14007  /**
14008  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14009  * var tpl = Roo.MasterTemplate.from('element-id');
14010  * @param {String/HTMLElement} el
14011  * @param {Object} config
14012  * @static
14013  */
14014 Roo.MasterTemplate.from = function(el, config){
14015     el = Roo.getDom(el);
14016     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14017 };/*
14018  * Based on:
14019  * Ext JS Library 1.1.1
14020  * Copyright(c) 2006-2007, Ext JS, LLC.
14021  *
14022  * Originally Released Under LGPL - original licence link has changed is not relivant.
14023  *
14024  * Fork - LGPL
14025  * <script type="text/javascript">
14026  */
14027
14028  
14029 /**
14030  * @class Roo.util.CSS
14031  * Utility class for manipulating CSS rules
14032  * @singleton
14033  */
14034 Roo.util.CSS = function(){
14035         var rules = null;
14036         var doc = document;
14037
14038     var camelRe = /(-[a-z])/gi;
14039     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14040
14041    return {
14042    /**
14043     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14044     * tag and appended to the HEAD of the document.
14045     * @param {String|Object} cssText The text containing the css rules
14046     * @param {String} id An id to add to the stylesheet for later removal
14047     * @return {StyleSheet}
14048     */
14049     createStyleSheet : function(cssText, id){
14050         var ss;
14051         var head = doc.getElementsByTagName("head")[0];
14052         var nrules = doc.createElement("style");
14053         nrules.setAttribute("type", "text/css");
14054         if(id){
14055             nrules.setAttribute("id", id);
14056         }
14057         if (typeof(cssText) != 'string') {
14058             // support object maps..
14059             // not sure if this a good idea.. 
14060             // perhaps it should be merged with the general css handling
14061             // and handle js style props.
14062             var cssTextNew = [];
14063             for(var n in cssText) {
14064                 var citems = [];
14065                 for(var k in cssText[n]) {
14066                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14067                 }
14068                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14069                 
14070             }
14071             cssText = cssTextNew.join("\n");
14072             
14073         }
14074        
14075        
14076        if(Roo.isIE){
14077            head.appendChild(nrules);
14078            ss = nrules.styleSheet;
14079            ss.cssText = cssText;
14080        }else{
14081            try{
14082                 nrules.appendChild(doc.createTextNode(cssText));
14083            }catch(e){
14084                nrules.cssText = cssText; 
14085            }
14086            head.appendChild(nrules);
14087            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14088        }
14089        this.cacheStyleSheet(ss);
14090        return ss;
14091    },
14092
14093    /**
14094     * Removes a style or link tag by id
14095     * @param {String} id The id of the tag
14096     */
14097    removeStyleSheet : function(id){
14098        var existing = doc.getElementById(id);
14099        if(existing){
14100            existing.parentNode.removeChild(existing);
14101        }
14102    },
14103
14104    /**
14105     * Dynamically swaps an existing stylesheet reference for a new one
14106     * @param {String} id The id of an existing link tag to remove
14107     * @param {String} url The href of the new stylesheet to include
14108     */
14109    swapStyleSheet : function(id, url){
14110        this.removeStyleSheet(id);
14111        var ss = doc.createElement("link");
14112        ss.setAttribute("rel", "stylesheet");
14113        ss.setAttribute("type", "text/css");
14114        ss.setAttribute("id", id);
14115        ss.setAttribute("href", url);
14116        doc.getElementsByTagName("head")[0].appendChild(ss);
14117    },
14118    
14119    /**
14120     * Refresh the rule cache if you have dynamically added stylesheets
14121     * @return {Object} An object (hash) of rules indexed by selector
14122     */
14123    refreshCache : function(){
14124        return this.getRules(true);
14125    },
14126
14127    // private
14128    cacheStyleSheet : function(stylesheet){
14129        if(!rules){
14130            rules = {};
14131        }
14132        try{// try catch for cross domain access issue
14133            var ssRules = stylesheet.cssRules || stylesheet.rules;
14134            for(var j = ssRules.length-1; j >= 0; --j){
14135                rules[ssRules[j].selectorText] = ssRules[j];
14136            }
14137        }catch(e){}
14138    },
14139    
14140    /**
14141     * Gets all css rules for the document
14142     * @param {Boolean} refreshCache true to refresh the internal cache
14143     * @return {Object} An object (hash) of rules indexed by selector
14144     */
14145    getRules : function(refreshCache){
14146                 if(rules == null || refreshCache){
14147                         rules = {};
14148                         var ds = doc.styleSheets;
14149                         for(var i =0, len = ds.length; i < len; i++){
14150                             try{
14151                         this.cacheStyleSheet(ds[i]);
14152                     }catch(e){} 
14153                 }
14154                 }
14155                 return rules;
14156         },
14157         
14158         /**
14159     * Gets an an individual CSS rule by selector(s)
14160     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14161     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14162     * @return {CSSRule} The CSS rule or null if one is not found
14163     */
14164    getRule : function(selector, refreshCache){
14165                 var rs = this.getRules(refreshCache);
14166                 if(!(selector instanceof Array)){
14167                     return rs[selector];
14168                 }
14169                 for(var i = 0; i < selector.length; i++){
14170                         if(rs[selector[i]]){
14171                                 return rs[selector[i]];
14172                         }
14173                 }
14174                 return null;
14175         },
14176         
14177         
14178         /**
14179     * Updates a rule property
14180     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14181     * @param {String} property The css property
14182     * @param {String} value The new value for the property
14183     * @return {Boolean} true If a rule was found and updated
14184     */
14185    updateRule : function(selector, property, value){
14186                 if(!(selector instanceof Array)){
14187                         var rule = this.getRule(selector);
14188                         if(rule){
14189                                 rule.style[property.replace(camelRe, camelFn)] = value;
14190                                 return true;
14191                         }
14192                 }else{
14193                         for(var i = 0; i < selector.length; i++){
14194                                 if(this.updateRule(selector[i], property, value)){
14195                                         return true;
14196                                 }
14197                         }
14198                 }
14199                 return false;
14200         }
14201    };   
14202 }();/*
14203  * Based on:
14204  * Ext JS Library 1.1.1
14205  * Copyright(c) 2006-2007, Ext JS, LLC.
14206  *
14207  * Originally Released Under LGPL - original licence link has changed is not relivant.
14208  *
14209  * Fork - LGPL
14210  * <script type="text/javascript">
14211  */
14212
14213  
14214
14215 /**
14216  * @class Roo.util.ClickRepeater
14217  * @extends Roo.util.Observable
14218  * 
14219  * A wrapper class which can be applied to any element. Fires a "click" event while the
14220  * mouse is pressed. The interval between firings may be specified in the config but
14221  * defaults to 10 milliseconds.
14222  * 
14223  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14224  * 
14225  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14226  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14227  * Similar to an autorepeat key delay.
14228  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14229  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14230  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14231  *           "interval" and "delay" are ignored. "immediate" is honored.
14232  * @cfg {Boolean} preventDefault True to prevent the default click event
14233  * @cfg {Boolean} stopDefault True to stop the default click event
14234  * 
14235  * @history
14236  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14237  *     2007-02-02 jvs Renamed to ClickRepeater
14238  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14239  *
14240  *  @constructor
14241  * @param {String/HTMLElement/Element} el The element to listen on
14242  * @param {Object} config
14243  **/
14244 Roo.util.ClickRepeater = function(el, config)
14245 {
14246     this.el = Roo.get(el);
14247     this.el.unselectable();
14248
14249     Roo.apply(this, config);
14250
14251     this.addEvents({
14252     /**
14253      * @event mousedown
14254      * Fires when the mouse button is depressed.
14255      * @param {Roo.util.ClickRepeater} this
14256      */
14257         "mousedown" : true,
14258     /**
14259      * @event click
14260      * Fires on a specified interval during the time the element is pressed.
14261      * @param {Roo.util.ClickRepeater} this
14262      */
14263         "click" : true,
14264     /**
14265      * @event mouseup
14266      * Fires when the mouse key is released.
14267      * @param {Roo.util.ClickRepeater} this
14268      */
14269         "mouseup" : true
14270     });
14271
14272     this.el.on("mousedown", this.handleMouseDown, this);
14273     if(this.preventDefault || this.stopDefault){
14274         this.el.on("click", function(e){
14275             if(this.preventDefault){
14276                 e.preventDefault();
14277             }
14278             if(this.stopDefault){
14279                 e.stopEvent();
14280             }
14281         }, this);
14282     }
14283
14284     // allow inline handler
14285     if(this.handler){
14286         this.on("click", this.handler,  this.scope || this);
14287     }
14288
14289     Roo.util.ClickRepeater.superclass.constructor.call(this);
14290 };
14291
14292 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14293     interval : 20,
14294     delay: 250,
14295     preventDefault : true,
14296     stopDefault : false,
14297     timer : 0,
14298
14299     // private
14300     handleMouseDown : function(){
14301         clearTimeout(this.timer);
14302         this.el.blur();
14303         if(this.pressClass){
14304             this.el.addClass(this.pressClass);
14305         }
14306         this.mousedownTime = new Date();
14307
14308         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14309         this.el.on("mouseout", this.handleMouseOut, this);
14310
14311         this.fireEvent("mousedown", this);
14312         this.fireEvent("click", this);
14313         
14314         this.timer = this.click.defer(this.delay || this.interval, this);
14315     },
14316
14317     // private
14318     click : function(){
14319         this.fireEvent("click", this);
14320         this.timer = this.click.defer(this.getInterval(), this);
14321     },
14322
14323     // private
14324     getInterval: function(){
14325         if(!this.accelerate){
14326             return this.interval;
14327         }
14328         var pressTime = this.mousedownTime.getElapsed();
14329         if(pressTime < 500){
14330             return 400;
14331         }else if(pressTime < 1700){
14332             return 320;
14333         }else if(pressTime < 2600){
14334             return 250;
14335         }else if(pressTime < 3500){
14336             return 180;
14337         }else if(pressTime < 4400){
14338             return 140;
14339         }else if(pressTime < 5300){
14340             return 80;
14341         }else if(pressTime < 6200){
14342             return 50;
14343         }else{
14344             return 10;
14345         }
14346     },
14347
14348     // private
14349     handleMouseOut : function(){
14350         clearTimeout(this.timer);
14351         if(this.pressClass){
14352             this.el.removeClass(this.pressClass);
14353         }
14354         this.el.on("mouseover", this.handleMouseReturn, this);
14355     },
14356
14357     // private
14358     handleMouseReturn : function(){
14359         this.el.un("mouseover", this.handleMouseReturn);
14360         if(this.pressClass){
14361             this.el.addClass(this.pressClass);
14362         }
14363         this.click();
14364     },
14365
14366     // private
14367     handleMouseUp : function(){
14368         clearTimeout(this.timer);
14369         this.el.un("mouseover", this.handleMouseReturn);
14370         this.el.un("mouseout", this.handleMouseOut);
14371         Roo.get(document).un("mouseup", this.handleMouseUp);
14372         this.el.removeClass(this.pressClass);
14373         this.fireEvent("mouseup", this);
14374     }
14375 });/*
14376  * Based on:
14377  * Ext JS Library 1.1.1
14378  * Copyright(c) 2006-2007, Ext JS, LLC.
14379  *
14380  * Originally Released Under LGPL - original licence link has changed is not relivant.
14381  *
14382  * Fork - LGPL
14383  * <script type="text/javascript">
14384  */
14385
14386  
14387 /**
14388  * @class Roo.KeyNav
14389  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14390  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14391  * way to implement custom navigation schemes for any UI component.</p>
14392  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14393  * pageUp, pageDown, del, home, end.  Usage:</p>
14394  <pre><code>
14395 var nav = new Roo.KeyNav("my-element", {
14396     "left" : function(e){
14397         this.moveLeft(e.ctrlKey);
14398     },
14399     "right" : function(e){
14400         this.moveRight(e.ctrlKey);
14401     },
14402     "enter" : function(e){
14403         this.save();
14404     },
14405     scope : this
14406 });
14407 </code></pre>
14408  * @constructor
14409  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14410  * @param {Object} config The config
14411  */
14412 Roo.KeyNav = function(el, config){
14413     this.el = Roo.get(el);
14414     Roo.apply(this, config);
14415     if(!this.disabled){
14416         this.disabled = true;
14417         this.enable();
14418     }
14419 };
14420
14421 Roo.KeyNav.prototype = {
14422     /**
14423      * @cfg {Boolean} disabled
14424      * True to disable this KeyNav instance (defaults to false)
14425      */
14426     disabled : false,
14427     /**
14428      * @cfg {String} defaultEventAction
14429      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14430      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14431      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14432      */
14433     defaultEventAction: "stopEvent",
14434     /**
14435      * @cfg {Boolean} forceKeyDown
14436      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14437      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14438      * handle keydown instead of keypress.
14439      */
14440     forceKeyDown : false,
14441
14442     // private
14443     prepareEvent : function(e){
14444         var k = e.getKey();
14445         var h = this.keyToHandler[k];
14446         //if(h && this[h]){
14447         //    e.stopPropagation();
14448         //}
14449         if(Roo.isSafari && h && k >= 37 && k <= 40){
14450             e.stopEvent();
14451         }
14452     },
14453
14454     // private
14455     relay : function(e){
14456         var k = e.getKey();
14457         var h = this.keyToHandler[k];
14458         if(h && this[h]){
14459             if(this.doRelay(e, this[h], h) !== true){
14460                 e[this.defaultEventAction]();
14461             }
14462         }
14463     },
14464
14465     // private
14466     doRelay : function(e, h, hname){
14467         return h.call(this.scope || this, e);
14468     },
14469
14470     // possible handlers
14471     enter : false,
14472     left : false,
14473     right : false,
14474     up : false,
14475     down : false,
14476     tab : false,
14477     esc : false,
14478     pageUp : false,
14479     pageDown : false,
14480     del : false,
14481     home : false,
14482     end : false,
14483
14484     // quick lookup hash
14485     keyToHandler : {
14486         37 : "left",
14487         39 : "right",
14488         38 : "up",
14489         40 : "down",
14490         33 : "pageUp",
14491         34 : "pageDown",
14492         46 : "del",
14493         36 : "home",
14494         35 : "end",
14495         13 : "enter",
14496         27 : "esc",
14497         9  : "tab"
14498     },
14499
14500         /**
14501          * Enable this KeyNav
14502          */
14503         enable: function(){
14504                 if(this.disabled){
14505             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14506             // the EventObject will normalize Safari automatically
14507             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14508                 this.el.on("keydown", this.relay,  this);
14509             }else{
14510                 this.el.on("keydown", this.prepareEvent,  this);
14511                 this.el.on("keypress", this.relay,  this);
14512             }
14513                     this.disabled = false;
14514                 }
14515         },
14516
14517         /**
14518          * Disable this KeyNav
14519          */
14520         disable: function(){
14521                 if(!this.disabled){
14522                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14523                 this.el.un("keydown", this.relay);
14524             }else{
14525                 this.el.un("keydown", this.prepareEvent);
14526                 this.el.un("keypress", this.relay);
14527             }
14528                     this.disabled = true;
14529                 }
14530         }
14531 };/*
14532  * Based on:
14533  * Ext JS Library 1.1.1
14534  * Copyright(c) 2006-2007, Ext JS, LLC.
14535  *
14536  * Originally Released Under LGPL - original licence link has changed is not relivant.
14537  *
14538  * Fork - LGPL
14539  * <script type="text/javascript">
14540  */
14541
14542  
14543 /**
14544  * @class Roo.KeyMap
14545  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14546  * The constructor accepts the same config object as defined by {@link #addBinding}.
14547  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14548  * combination it will call the function with this signature (if the match is a multi-key
14549  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14550  * A KeyMap can also handle a string representation of keys.<br />
14551  * Usage:
14552  <pre><code>
14553 // map one key by key code
14554 var map = new Roo.KeyMap("my-element", {
14555     key: 13, // or Roo.EventObject.ENTER
14556     fn: myHandler,
14557     scope: myObject
14558 });
14559
14560 // map multiple keys to one action by string
14561 var map = new Roo.KeyMap("my-element", {
14562     key: "a\r\n\t",
14563     fn: myHandler,
14564     scope: myObject
14565 });
14566
14567 // map multiple keys to multiple actions by strings and array of codes
14568 var map = new Roo.KeyMap("my-element", [
14569     {
14570         key: [10,13],
14571         fn: function(){ alert("Return was pressed"); }
14572     }, {
14573         key: "abc",
14574         fn: function(){ alert('a, b or c was pressed'); }
14575     }, {
14576         key: "\t",
14577         ctrl:true,
14578         shift:true,
14579         fn: function(){ alert('Control + shift + tab was pressed.'); }
14580     }
14581 ]);
14582 </code></pre>
14583  * <b>Note: A KeyMap starts enabled</b>
14584  * @constructor
14585  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14586  * @param {Object} config The config (see {@link #addBinding})
14587  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14588  */
14589 Roo.KeyMap = function(el, config, eventName){
14590     this.el  = Roo.get(el);
14591     this.eventName = eventName || "keydown";
14592     this.bindings = [];
14593     if(config){
14594         this.addBinding(config);
14595     }
14596     this.enable();
14597 };
14598
14599 Roo.KeyMap.prototype = {
14600     /**
14601      * True to stop the event from bubbling and prevent the default browser action if the
14602      * key was handled by the KeyMap (defaults to false)
14603      * @type Boolean
14604      */
14605     stopEvent : false,
14606
14607     /**
14608      * Add a new binding to this KeyMap. The following config object properties are supported:
14609      * <pre>
14610 Property    Type             Description
14611 ----------  ---------------  ----------------------------------------------------------------------
14612 key         String/Array     A single keycode or an array of keycodes to handle
14613 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14614 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14615 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14616 fn          Function         The function to call when KeyMap finds the expected key combination
14617 scope       Object           The scope of the callback function
14618 </pre>
14619      *
14620      * Usage:
14621      * <pre><code>
14622 // Create a KeyMap
14623 var map = new Roo.KeyMap(document, {
14624     key: Roo.EventObject.ENTER,
14625     fn: handleKey,
14626     scope: this
14627 });
14628
14629 //Add a new binding to the existing KeyMap later
14630 map.addBinding({
14631     key: 'abc',
14632     shift: true,
14633     fn: handleKey,
14634     scope: this
14635 });
14636 </code></pre>
14637      * @param {Object/Array} config A single KeyMap config or an array of configs
14638      */
14639         addBinding : function(config){
14640         if(config instanceof Array){
14641             for(var i = 0, len = config.length; i < len; i++){
14642                 this.addBinding(config[i]);
14643             }
14644             return;
14645         }
14646         var keyCode = config.key,
14647             shift = config.shift, 
14648             ctrl = config.ctrl, 
14649             alt = config.alt,
14650             fn = config.fn,
14651             scope = config.scope;
14652         if(typeof keyCode == "string"){
14653             var ks = [];
14654             var keyString = keyCode.toUpperCase();
14655             for(var j = 0, len = keyString.length; j < len; j++){
14656                 ks.push(keyString.charCodeAt(j));
14657             }
14658             keyCode = ks;
14659         }
14660         var keyArray = keyCode instanceof Array;
14661         var handler = function(e){
14662             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14663                 var k = e.getKey();
14664                 if(keyArray){
14665                     for(var i = 0, len = keyCode.length; i < len; i++){
14666                         if(keyCode[i] == k){
14667                           if(this.stopEvent){
14668                               e.stopEvent();
14669                           }
14670                           fn.call(scope || window, k, e);
14671                           return;
14672                         }
14673                     }
14674                 }else{
14675                     if(k == keyCode){
14676                         if(this.stopEvent){
14677                            e.stopEvent();
14678                         }
14679                         fn.call(scope || window, k, e);
14680                     }
14681                 }
14682             }
14683         };
14684         this.bindings.push(handler);  
14685         },
14686
14687     /**
14688      * Shorthand for adding a single key listener
14689      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14690      * following options:
14691      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14692      * @param {Function} fn The function to call
14693      * @param {Object} scope (optional) The scope of the function
14694      */
14695     on : function(key, fn, scope){
14696         var keyCode, shift, ctrl, alt;
14697         if(typeof key == "object" && !(key instanceof Array)){
14698             keyCode = key.key;
14699             shift = key.shift;
14700             ctrl = key.ctrl;
14701             alt = key.alt;
14702         }else{
14703             keyCode = key;
14704         }
14705         this.addBinding({
14706             key: keyCode,
14707             shift: shift,
14708             ctrl: ctrl,
14709             alt: alt,
14710             fn: fn,
14711             scope: scope
14712         })
14713     },
14714
14715     // private
14716     handleKeyDown : function(e){
14717             if(this.enabled){ //just in case
14718             var b = this.bindings;
14719             for(var i = 0, len = b.length; i < len; i++){
14720                 b[i].call(this, e);
14721             }
14722             }
14723         },
14724         
14725         /**
14726          * Returns true if this KeyMap is enabled
14727          * @return {Boolean} 
14728          */
14729         isEnabled : function(){
14730             return this.enabled;  
14731         },
14732         
14733         /**
14734          * Enables this KeyMap
14735          */
14736         enable: function(){
14737                 if(!this.enabled){
14738                     this.el.on(this.eventName, this.handleKeyDown, this);
14739                     this.enabled = true;
14740                 }
14741         },
14742
14743         /**
14744          * Disable this KeyMap
14745          */
14746         disable: function(){
14747                 if(this.enabled){
14748                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14749                     this.enabled = false;
14750                 }
14751         }
14752 };/*
14753  * Based on:
14754  * Ext JS Library 1.1.1
14755  * Copyright(c) 2006-2007, Ext JS, LLC.
14756  *
14757  * Originally Released Under LGPL - original licence link has changed is not relivant.
14758  *
14759  * Fork - LGPL
14760  * <script type="text/javascript">
14761  */
14762
14763  
14764 /**
14765  * @class Roo.util.TextMetrics
14766  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14767  * wide, in pixels, a given block of text will be.
14768  * @singleton
14769  */
14770 Roo.util.TextMetrics = function(){
14771     var shared;
14772     return {
14773         /**
14774          * Measures the size of the specified text
14775          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14776          * that can affect the size of the rendered text
14777          * @param {String} text The text to measure
14778          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14779          * in order to accurately measure the text height
14780          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14781          */
14782         measure : function(el, text, fixedWidth){
14783             if(!shared){
14784                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14785             }
14786             shared.bind(el);
14787             shared.setFixedWidth(fixedWidth || 'auto');
14788             return shared.getSize(text);
14789         },
14790
14791         /**
14792          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14793          * the overhead of multiple calls to initialize the style properties on each measurement.
14794          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14795          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14796          * in order to accurately measure the text height
14797          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14798          */
14799         createInstance : function(el, fixedWidth){
14800             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14801         }
14802     };
14803 }();
14804
14805  
14806
14807 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14808     var ml = new Roo.Element(document.createElement('div'));
14809     document.body.appendChild(ml.dom);
14810     ml.position('absolute');
14811     ml.setLeftTop(-1000, -1000);
14812     ml.hide();
14813
14814     if(fixedWidth){
14815         ml.setWidth(fixedWidth);
14816     }
14817      
14818     var instance = {
14819         /**
14820          * Returns the size of the specified text based on the internal element's style and width properties
14821          * @memberOf Roo.util.TextMetrics.Instance#
14822          * @param {String} text The text to measure
14823          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14824          */
14825         getSize : function(text){
14826             ml.update(text);
14827             var s = ml.getSize();
14828             ml.update('');
14829             return s;
14830         },
14831
14832         /**
14833          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14834          * that can affect the size of the rendered text
14835          * @memberOf Roo.util.TextMetrics.Instance#
14836          * @param {String/HTMLElement} el The element, dom node or id
14837          */
14838         bind : function(el){
14839             ml.setStyle(
14840                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14841             );
14842         },
14843
14844         /**
14845          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14846          * to set a fixed width in order to accurately measure the text height.
14847          * @memberOf Roo.util.TextMetrics.Instance#
14848          * @param {Number} width The width to set on the element
14849          */
14850         setFixedWidth : function(width){
14851             ml.setWidth(width);
14852         },
14853
14854         /**
14855          * Returns the measured width of the specified text
14856          * @memberOf Roo.util.TextMetrics.Instance#
14857          * @param {String} text The text to measure
14858          * @return {Number} width The width in pixels
14859          */
14860         getWidth : function(text){
14861             ml.dom.style.width = 'auto';
14862             return this.getSize(text).width;
14863         },
14864
14865         /**
14866          * Returns the measured height of the specified text.  For multiline text, be sure to call
14867          * {@link #setFixedWidth} if necessary.
14868          * @memberOf Roo.util.TextMetrics.Instance#
14869          * @param {String} text The text to measure
14870          * @return {Number} height The height in pixels
14871          */
14872         getHeight : function(text){
14873             return this.getSize(text).height;
14874         }
14875     };
14876
14877     instance.bind(bindTo);
14878
14879     return instance;
14880 };
14881
14882 // backwards compat
14883 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14884  * Based on:
14885  * Ext JS Library 1.1.1
14886  * Copyright(c) 2006-2007, Ext JS, LLC.
14887  *
14888  * Originally Released Under LGPL - original licence link has changed is not relivant.
14889  *
14890  * Fork - LGPL
14891  * <script type="text/javascript">
14892  */
14893
14894 /**
14895  * @class Roo.state.Provider
14896  * Abstract base class for state provider implementations. This class provides methods
14897  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14898  * Provider interface.
14899  */
14900 Roo.state.Provider = function(){
14901     /**
14902      * @event statechange
14903      * Fires when a state change occurs.
14904      * @param {Provider} this This state provider
14905      * @param {String} key The state key which was changed
14906      * @param {String} value The encoded value for the state
14907      */
14908     this.addEvents({
14909         "statechange": true
14910     });
14911     this.state = {};
14912     Roo.state.Provider.superclass.constructor.call(this);
14913 };
14914 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14915     /**
14916      * Returns the current value for a key
14917      * @param {String} name The key name
14918      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14919      * @return {Mixed} The state data
14920      */
14921     get : function(name, defaultValue){
14922         return typeof this.state[name] == "undefined" ?
14923             defaultValue : this.state[name];
14924     },
14925     
14926     /**
14927      * Clears a value from the state
14928      * @param {String} name The key name
14929      */
14930     clear : function(name){
14931         delete this.state[name];
14932         this.fireEvent("statechange", this, name, null);
14933     },
14934     
14935     /**
14936      * Sets the value for a key
14937      * @param {String} name The key name
14938      * @param {Mixed} value The value to set
14939      */
14940     set : function(name, value){
14941         this.state[name] = value;
14942         this.fireEvent("statechange", this, name, value);
14943     },
14944     
14945     /**
14946      * Decodes a string previously encoded with {@link #encodeValue}.
14947      * @param {String} value The value to decode
14948      * @return {Mixed} The decoded value
14949      */
14950     decodeValue : function(cookie){
14951         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14952         var matches = re.exec(unescape(cookie));
14953         if(!matches || !matches[1]) {
14954             return; // non state cookie
14955         }
14956         var type = matches[1];
14957         var v = matches[2];
14958         switch(type){
14959             case "n":
14960                 return parseFloat(v);
14961             case "d":
14962                 return new Date(Date.parse(v));
14963             case "b":
14964                 return (v == "1");
14965             case "a":
14966                 var all = [];
14967                 var values = v.split("^");
14968                 for(var i = 0, len = values.length; i < len; i++){
14969                     all.push(this.decodeValue(values[i]));
14970                 }
14971                 return all;
14972            case "o":
14973                 var all = {};
14974                 var values = v.split("^");
14975                 for(var i = 0, len = values.length; i < len; i++){
14976                     var kv = values[i].split("=");
14977                     all[kv[0]] = this.decodeValue(kv[1]);
14978                 }
14979                 return all;
14980            default:
14981                 return v;
14982         }
14983     },
14984     
14985     /**
14986      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14987      * @param {Mixed} value The value to encode
14988      * @return {String} The encoded value
14989      */
14990     encodeValue : function(v){
14991         var enc;
14992         if(typeof v == "number"){
14993             enc = "n:" + v;
14994         }else if(typeof v == "boolean"){
14995             enc = "b:" + (v ? "1" : "0");
14996         }else if(v instanceof Date){
14997             enc = "d:" + v.toGMTString();
14998         }else if(v instanceof Array){
14999             var flat = "";
15000             for(var i = 0, len = v.length; i < len; i++){
15001                 flat += this.encodeValue(v[i]);
15002                 if(i != len-1) {
15003                     flat += "^";
15004                 }
15005             }
15006             enc = "a:" + flat;
15007         }else if(typeof v == "object"){
15008             var flat = "";
15009             for(var key in v){
15010                 if(typeof v[key] != "function"){
15011                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15012                 }
15013             }
15014             enc = "o:" + flat.substring(0, flat.length-1);
15015         }else{
15016             enc = "s:" + v;
15017         }
15018         return escape(enc);        
15019     }
15020 });
15021
15022 /*
15023  * Based on:
15024  * Ext JS Library 1.1.1
15025  * Copyright(c) 2006-2007, Ext JS, LLC.
15026  *
15027  * Originally Released Under LGPL - original licence link has changed is not relivant.
15028  *
15029  * Fork - LGPL
15030  * <script type="text/javascript">
15031  */
15032 /**
15033  * @class Roo.state.Manager
15034  * This is the global state manager. By default all components that are "state aware" check this class
15035  * for state information if you don't pass them a custom state provider. In order for this class
15036  * to be useful, it must be initialized with a provider when your application initializes.
15037  <pre><code>
15038 // in your initialization function
15039 init : function(){
15040    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15041    ...
15042    // supposed you have a {@link Roo.BorderLayout}
15043    var layout = new Roo.BorderLayout(...);
15044    layout.restoreState();
15045    // or a {Roo.BasicDialog}
15046    var dialog = new Roo.BasicDialog(...);
15047    dialog.restoreState();
15048  </code></pre>
15049  * @singleton
15050  */
15051 Roo.state.Manager = function(){
15052     var provider = new Roo.state.Provider();
15053     
15054     return {
15055         /**
15056          * Configures the default state provider for your application
15057          * @param {Provider} stateProvider The state provider to set
15058          */
15059         setProvider : function(stateProvider){
15060             provider = stateProvider;
15061         },
15062         
15063         /**
15064          * Returns the current value for a key
15065          * @param {String} name The key name
15066          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15067          * @return {Mixed} The state data
15068          */
15069         get : function(key, defaultValue){
15070             return provider.get(key, defaultValue);
15071         },
15072         
15073         /**
15074          * Sets the value for a key
15075          * @param {String} name The key name
15076          * @param {Mixed} value The state data
15077          */
15078          set : function(key, value){
15079             provider.set(key, value);
15080         },
15081         
15082         /**
15083          * Clears a value from the state
15084          * @param {String} name The key name
15085          */
15086         clear : function(key){
15087             provider.clear(key);
15088         },
15089         
15090         /**
15091          * Gets the currently configured state provider
15092          * @return {Provider} The state provider
15093          */
15094         getProvider : function(){
15095             return provider;
15096         }
15097     };
15098 }();
15099 /*
15100  * Based on:
15101  * Ext JS Library 1.1.1
15102  * Copyright(c) 2006-2007, Ext JS, LLC.
15103  *
15104  * Originally Released Under LGPL - original licence link has changed is not relivant.
15105  *
15106  * Fork - LGPL
15107  * <script type="text/javascript">
15108  */
15109 /**
15110  * @class Roo.state.CookieProvider
15111  * @extends Roo.state.Provider
15112  * The default Provider implementation which saves state via cookies.
15113  * <br />Usage:
15114  <pre><code>
15115    var cp = new Roo.state.CookieProvider({
15116        path: "/cgi-bin/",
15117        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15118        domain: "roojs.com"
15119    })
15120    Roo.state.Manager.setProvider(cp);
15121  </code></pre>
15122  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15123  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15124  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15125  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15126  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15127  * domain the page is running on including the 'www' like 'www.roojs.com')
15128  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15129  * @constructor
15130  * Create a new CookieProvider
15131  * @param {Object} config The configuration object
15132  */
15133 Roo.state.CookieProvider = function(config){
15134     Roo.state.CookieProvider.superclass.constructor.call(this);
15135     this.path = "/";
15136     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15137     this.domain = null;
15138     this.secure = false;
15139     Roo.apply(this, config);
15140     this.state = this.readCookies();
15141 };
15142
15143 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15144     // private
15145     set : function(name, value){
15146         if(typeof value == "undefined" || value === null){
15147             this.clear(name);
15148             return;
15149         }
15150         this.setCookie(name, value);
15151         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15152     },
15153
15154     // private
15155     clear : function(name){
15156         this.clearCookie(name);
15157         Roo.state.CookieProvider.superclass.clear.call(this, name);
15158     },
15159
15160     // private
15161     readCookies : function(){
15162         var cookies = {};
15163         var c = document.cookie + ";";
15164         var re = /\s?(.*?)=(.*?);/g;
15165         var matches;
15166         while((matches = re.exec(c)) != null){
15167             var name = matches[1];
15168             var value = matches[2];
15169             if(name && name.substring(0,3) == "ys-"){
15170                 cookies[name.substr(3)] = this.decodeValue(value);
15171             }
15172         }
15173         return cookies;
15174     },
15175
15176     // private
15177     setCookie : function(name, value){
15178         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15179            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15180            ((this.path == null) ? "" : ("; path=" + this.path)) +
15181            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15182            ((this.secure == true) ? "; secure" : "");
15183     },
15184
15185     // private
15186     clearCookie : function(name){
15187         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15188            ((this.path == null) ? "" : ("; path=" + this.path)) +
15189            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15190            ((this.secure == true) ? "; secure" : "");
15191     }
15192 });/*
15193  * Based on:
15194  * Ext JS Library 1.1.1
15195  * Copyright(c) 2006-2007, Ext JS, LLC.
15196  *
15197  * Originally Released Under LGPL - original licence link has changed is not relivant.
15198  *
15199  * Fork - LGPL
15200  * <script type="text/javascript">
15201  */
15202  
15203
15204 /**
15205  * @class Roo.ComponentMgr
15206  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15207  * @singleton
15208  */
15209 Roo.ComponentMgr = function(){
15210     var all = new Roo.util.MixedCollection();
15211
15212     return {
15213         /**
15214          * Registers a component.
15215          * @param {Roo.Component} c The component
15216          */
15217         register : function(c){
15218             all.add(c);
15219         },
15220
15221         /**
15222          * Unregisters a component.
15223          * @param {Roo.Component} c The component
15224          */
15225         unregister : function(c){
15226             all.remove(c);
15227         },
15228
15229         /**
15230          * Returns a component by id
15231          * @param {String} id The component id
15232          */
15233         get : function(id){
15234             return all.get(id);
15235         },
15236
15237         /**
15238          * Registers a function that will be called when a specified component is added to ComponentMgr
15239          * @param {String} id The component id
15240          * @param {Funtction} fn The callback function
15241          * @param {Object} scope The scope of the callback
15242          */
15243         onAvailable : function(id, fn, scope){
15244             all.on("add", function(index, o){
15245                 if(o.id == id){
15246                     fn.call(scope || o, o);
15247                     all.un("add", fn, scope);
15248                 }
15249             });
15250         }
15251     };
15252 }();/*
15253  * Based on:
15254  * Ext JS Library 1.1.1
15255  * Copyright(c) 2006-2007, Ext JS, LLC.
15256  *
15257  * Originally Released Under LGPL - original licence link has changed is not relivant.
15258  *
15259  * Fork - LGPL
15260  * <script type="text/javascript">
15261  */
15262  
15263 /**
15264  * @class Roo.Component
15265  * @extends Roo.util.Observable
15266  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15267  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15268  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15269  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15270  * All visual components (widgets) that require rendering into a layout should subclass Component.
15271  * @constructor
15272  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15273  * 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
15274  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15275  */
15276 Roo.Component = function(config){
15277     config = config || {};
15278     if(config.tagName || config.dom || typeof config == "string"){ // element object
15279         config = {el: config, id: config.id || config};
15280     }
15281     this.initialConfig = config;
15282
15283     Roo.apply(this, config);
15284     this.addEvents({
15285         /**
15286          * @event disable
15287          * Fires after the component is disabled.
15288              * @param {Roo.Component} this
15289              */
15290         disable : true,
15291         /**
15292          * @event enable
15293          * Fires after the component is enabled.
15294              * @param {Roo.Component} this
15295              */
15296         enable : true,
15297         /**
15298          * @event beforeshow
15299          * Fires before the component is shown.  Return false to stop the show.
15300              * @param {Roo.Component} this
15301              */
15302         beforeshow : true,
15303         /**
15304          * @event show
15305          * Fires after the component is shown.
15306              * @param {Roo.Component} this
15307              */
15308         show : true,
15309         /**
15310          * @event beforehide
15311          * Fires before the component is hidden. Return false to stop the hide.
15312              * @param {Roo.Component} this
15313              */
15314         beforehide : true,
15315         /**
15316          * @event hide
15317          * Fires after the component is hidden.
15318              * @param {Roo.Component} this
15319              */
15320         hide : true,
15321         /**
15322          * @event beforerender
15323          * Fires before the component is rendered. Return false to stop the render.
15324              * @param {Roo.Component} this
15325              */
15326         beforerender : true,
15327         /**
15328          * @event render
15329          * Fires after the component is rendered.
15330              * @param {Roo.Component} this
15331              */
15332         render : true,
15333         /**
15334          * @event beforedestroy
15335          * Fires before the component is destroyed. Return false to stop the destroy.
15336              * @param {Roo.Component} this
15337              */
15338         beforedestroy : true,
15339         /**
15340          * @event destroy
15341          * Fires after the component is destroyed.
15342              * @param {Roo.Component} this
15343              */
15344         destroy : true
15345     });
15346     if(!this.id){
15347         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15348     }
15349     Roo.ComponentMgr.register(this);
15350     Roo.Component.superclass.constructor.call(this);
15351     this.initComponent();
15352     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15353         this.render(this.renderTo);
15354         delete this.renderTo;
15355     }
15356 };
15357
15358 /** @private */
15359 Roo.Component.AUTO_ID = 1000;
15360
15361 Roo.extend(Roo.Component, Roo.util.Observable, {
15362     /**
15363      * @scope Roo.Component.prototype
15364      * @type {Boolean}
15365      * true if this component is hidden. Read-only.
15366      */
15367     hidden : false,
15368     /**
15369      * @type {Boolean}
15370      * true if this component is disabled. Read-only.
15371      */
15372     disabled : false,
15373     /**
15374      * @type {Boolean}
15375      * true if this component has been rendered. Read-only.
15376      */
15377     rendered : false,
15378     
15379     /** @cfg {String} disableClass
15380      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15381      */
15382     disabledClass : "x-item-disabled",
15383         /** @cfg {Boolean} allowDomMove
15384          * Whether the component can move the Dom node when rendering (defaults to true).
15385          */
15386     allowDomMove : true,
15387     /** @cfg {String} hideMode (display|visibility)
15388      * How this component should hidden. Supported values are
15389      * "visibility" (css visibility), "offsets" (negative offset position) and
15390      * "display" (css display) - defaults to "display".
15391      */
15392     hideMode: 'display',
15393
15394     /** @private */
15395     ctype : "Roo.Component",
15396
15397     /**
15398      * @cfg {String} actionMode 
15399      * which property holds the element that used for  hide() / show() / disable() / enable()
15400      * default is 'el' 
15401      */
15402     actionMode : "el",
15403
15404     /** @private */
15405     getActionEl : function(){
15406         return this[this.actionMode];
15407     },
15408
15409     initComponent : Roo.emptyFn,
15410     /**
15411      * If this is a lazy rendering component, render it to its container element.
15412      * @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.
15413      */
15414     render : function(container, position){
15415         
15416         if(this.rendered){
15417             return this;
15418         }
15419         
15420         if(this.fireEvent("beforerender", this) === false){
15421             return false;
15422         }
15423         
15424         if(!container && this.el){
15425             this.el = Roo.get(this.el);
15426             container = this.el.dom.parentNode;
15427             this.allowDomMove = false;
15428         }
15429         this.container = Roo.get(container);
15430         this.rendered = true;
15431         if(position !== undefined){
15432             if(typeof position == 'number'){
15433                 position = this.container.dom.childNodes[position];
15434             }else{
15435                 position = Roo.getDom(position);
15436             }
15437         }
15438         this.onRender(this.container, position || null);
15439         if(this.cls){
15440             this.el.addClass(this.cls);
15441             delete this.cls;
15442         }
15443         if(this.style){
15444             this.el.applyStyles(this.style);
15445             delete this.style;
15446         }
15447         this.fireEvent("render", this);
15448         this.afterRender(this.container);
15449         if(this.hidden){
15450             this.hide();
15451         }
15452         if(this.disabled){
15453             this.disable();
15454         }
15455
15456         return this;
15457         
15458     },
15459
15460     /** @private */
15461     // default function is not really useful
15462     onRender : function(ct, position){
15463         if(this.el){
15464             this.el = Roo.get(this.el);
15465             if(this.allowDomMove !== false){
15466                 ct.dom.insertBefore(this.el.dom, position);
15467             }
15468         }
15469     },
15470
15471     /** @private */
15472     getAutoCreate : function(){
15473         var cfg = typeof this.autoCreate == "object" ?
15474                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15475         if(this.id && !cfg.id){
15476             cfg.id = this.id;
15477         }
15478         return cfg;
15479     },
15480
15481     /** @private */
15482     afterRender : Roo.emptyFn,
15483
15484     /**
15485      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15486      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15487      */
15488     destroy : function(){
15489         if(this.fireEvent("beforedestroy", this) !== false){
15490             this.purgeListeners();
15491             this.beforeDestroy();
15492             if(this.rendered){
15493                 this.el.removeAllListeners();
15494                 this.el.remove();
15495                 if(this.actionMode == "container"){
15496                     this.container.remove();
15497                 }
15498             }
15499             this.onDestroy();
15500             Roo.ComponentMgr.unregister(this);
15501             this.fireEvent("destroy", this);
15502         }
15503     },
15504
15505         /** @private */
15506     beforeDestroy : function(){
15507
15508     },
15509
15510         /** @private */
15511         onDestroy : function(){
15512
15513     },
15514
15515     /**
15516      * Returns the underlying {@link Roo.Element}.
15517      * @return {Roo.Element} The element
15518      */
15519     getEl : function(){
15520         return this.el;
15521     },
15522
15523     /**
15524      * Returns the id of this component.
15525      * @return {String}
15526      */
15527     getId : function(){
15528         return this.id;
15529     },
15530
15531     /**
15532      * Try to focus this component.
15533      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15534      * @return {Roo.Component} this
15535      */
15536     focus : function(selectText){
15537         if(this.rendered){
15538             this.el.focus();
15539             if(selectText === true){
15540                 this.el.dom.select();
15541             }
15542         }
15543         return this;
15544     },
15545
15546     /** @private */
15547     blur : function(){
15548         if(this.rendered){
15549             this.el.blur();
15550         }
15551         return this;
15552     },
15553
15554     /**
15555      * Disable this component.
15556      * @return {Roo.Component} this
15557      */
15558     disable : function(){
15559         if(this.rendered){
15560             this.onDisable();
15561         }
15562         this.disabled = true;
15563         this.fireEvent("disable", this);
15564         return this;
15565     },
15566
15567         // private
15568     onDisable : function(){
15569         this.getActionEl().addClass(this.disabledClass);
15570         this.el.dom.disabled = true;
15571     },
15572
15573     /**
15574      * Enable this component.
15575      * @return {Roo.Component} this
15576      */
15577     enable : function(){
15578         if(this.rendered){
15579             this.onEnable();
15580         }
15581         this.disabled = false;
15582         this.fireEvent("enable", this);
15583         return this;
15584     },
15585
15586         // private
15587     onEnable : function(){
15588         this.getActionEl().removeClass(this.disabledClass);
15589         this.el.dom.disabled = false;
15590     },
15591
15592     /**
15593      * Convenience function for setting disabled/enabled by boolean.
15594      * @param {Boolean} disabled
15595      */
15596     setDisabled : function(disabled){
15597         this[disabled ? "disable" : "enable"]();
15598     },
15599
15600     /**
15601      * Show this component.
15602      * @return {Roo.Component} this
15603      */
15604     show: function(){
15605         if(this.fireEvent("beforeshow", this) !== false){
15606             this.hidden = false;
15607             if(this.rendered){
15608                 this.onShow();
15609             }
15610             this.fireEvent("show", this);
15611         }
15612         return this;
15613     },
15614
15615     // private
15616     onShow : function(){
15617         var ae = this.getActionEl();
15618         if(this.hideMode == 'visibility'){
15619             ae.dom.style.visibility = "visible";
15620         }else if(this.hideMode == 'offsets'){
15621             ae.removeClass('x-hidden');
15622         }else{
15623             ae.dom.style.display = "";
15624         }
15625     },
15626
15627     /**
15628      * Hide this component.
15629      * @return {Roo.Component} this
15630      */
15631     hide: function(){
15632         if(this.fireEvent("beforehide", this) !== false){
15633             this.hidden = true;
15634             if(this.rendered){
15635                 this.onHide();
15636             }
15637             this.fireEvent("hide", this);
15638         }
15639         return this;
15640     },
15641
15642     // private
15643     onHide : function(){
15644         var ae = this.getActionEl();
15645         if(this.hideMode == 'visibility'){
15646             ae.dom.style.visibility = "hidden";
15647         }else if(this.hideMode == 'offsets'){
15648             ae.addClass('x-hidden');
15649         }else{
15650             ae.dom.style.display = "none";
15651         }
15652     },
15653
15654     /**
15655      * Convenience function to hide or show this component by boolean.
15656      * @param {Boolean} visible True to show, false to hide
15657      * @return {Roo.Component} this
15658      */
15659     setVisible: function(visible){
15660         if(visible) {
15661             this.show();
15662         }else{
15663             this.hide();
15664         }
15665         return this;
15666     },
15667
15668     /**
15669      * Returns true if this component is visible.
15670      */
15671     isVisible : function(){
15672         return this.getActionEl().isVisible();
15673     },
15674
15675     cloneConfig : function(overrides){
15676         overrides = overrides || {};
15677         var id = overrides.id || Roo.id();
15678         var cfg = Roo.applyIf(overrides, this.initialConfig);
15679         cfg.id = id; // prevent dup id
15680         return new this.constructor(cfg);
15681     }
15682 });/*
15683  * Based on:
15684  * Ext JS Library 1.1.1
15685  * Copyright(c) 2006-2007, Ext JS, LLC.
15686  *
15687  * Originally Released Under LGPL - original licence link has changed is not relivant.
15688  *
15689  * Fork - LGPL
15690  * <script type="text/javascript">
15691  */
15692
15693 /**
15694  * @class Roo.BoxComponent
15695  * @extends Roo.Component
15696  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15697  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15698  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15699  * layout containers.
15700  * @constructor
15701  * @param {Roo.Element/String/Object} config The configuration options.
15702  */
15703 Roo.BoxComponent = function(config){
15704     Roo.Component.call(this, config);
15705     this.addEvents({
15706         /**
15707          * @event resize
15708          * Fires after the component is resized.
15709              * @param {Roo.Component} this
15710              * @param {Number} adjWidth The box-adjusted width that was set
15711              * @param {Number} adjHeight The box-adjusted height that was set
15712              * @param {Number} rawWidth The width that was originally specified
15713              * @param {Number} rawHeight The height that was originally specified
15714              */
15715         resize : true,
15716         /**
15717          * @event move
15718          * Fires after the component is moved.
15719              * @param {Roo.Component} this
15720              * @param {Number} x The new x position
15721              * @param {Number} y The new y position
15722              */
15723         move : true
15724     });
15725 };
15726
15727 Roo.extend(Roo.BoxComponent, Roo.Component, {
15728     // private, set in afterRender to signify that the component has been rendered
15729     boxReady : false,
15730     // private, used to defer height settings to subclasses
15731     deferHeight: false,
15732     /** @cfg {Number} width
15733      * width (optional) size of component
15734      */
15735      /** @cfg {Number} height
15736      * height (optional) size of component
15737      */
15738      
15739     /**
15740      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15741      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15742      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15743      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15744      * @return {Roo.BoxComponent} this
15745      */
15746     setSize : function(w, h){
15747         // support for standard size objects
15748         if(typeof w == 'object'){
15749             h = w.height;
15750             w = w.width;
15751         }
15752         // not rendered
15753         if(!this.boxReady){
15754             this.width = w;
15755             this.height = h;
15756             return this;
15757         }
15758
15759         // prevent recalcs when not needed
15760         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15761             return this;
15762         }
15763         this.lastSize = {width: w, height: h};
15764
15765         var adj = this.adjustSize(w, h);
15766         var aw = adj.width, ah = adj.height;
15767         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15768             var rz = this.getResizeEl();
15769             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15770                 rz.setSize(aw, ah);
15771             }else if(!this.deferHeight && ah !== undefined){
15772                 rz.setHeight(ah);
15773             }else if(aw !== undefined){
15774                 rz.setWidth(aw);
15775             }
15776             this.onResize(aw, ah, w, h);
15777             this.fireEvent('resize', this, aw, ah, w, h);
15778         }
15779         return this;
15780     },
15781
15782     /**
15783      * Gets the current size of the component's underlying element.
15784      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15785      */
15786     getSize : function(){
15787         return this.el.getSize();
15788     },
15789
15790     /**
15791      * Gets the current XY position of the component's underlying element.
15792      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15793      * @return {Array} The XY position of the element (e.g., [100, 200])
15794      */
15795     getPosition : function(local){
15796         if(local === true){
15797             return [this.el.getLeft(true), this.el.getTop(true)];
15798         }
15799         return this.xy || this.el.getXY();
15800     },
15801
15802     /**
15803      * Gets the current box measurements of the component's underlying element.
15804      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15805      * @returns {Object} box An object in the format {x, y, width, height}
15806      */
15807     getBox : function(local){
15808         var s = this.el.getSize();
15809         if(local){
15810             s.x = this.el.getLeft(true);
15811             s.y = this.el.getTop(true);
15812         }else{
15813             var xy = this.xy || this.el.getXY();
15814             s.x = xy[0];
15815             s.y = xy[1];
15816         }
15817         return s;
15818     },
15819
15820     /**
15821      * Sets the current box measurements of the component's underlying element.
15822      * @param {Object} box An object in the format {x, y, width, height}
15823      * @returns {Roo.BoxComponent} this
15824      */
15825     updateBox : function(box){
15826         this.setSize(box.width, box.height);
15827         this.setPagePosition(box.x, box.y);
15828         return this;
15829     },
15830
15831     // protected
15832     getResizeEl : function(){
15833         return this.resizeEl || this.el;
15834     },
15835
15836     // protected
15837     getPositionEl : function(){
15838         return this.positionEl || this.el;
15839     },
15840
15841     /**
15842      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15843      * This method fires the move event.
15844      * @param {Number} left The new left
15845      * @param {Number} top The new top
15846      * @returns {Roo.BoxComponent} this
15847      */
15848     setPosition : function(x, y){
15849         this.x = x;
15850         this.y = y;
15851         if(!this.boxReady){
15852             return this;
15853         }
15854         var adj = this.adjustPosition(x, y);
15855         var ax = adj.x, ay = adj.y;
15856
15857         var el = this.getPositionEl();
15858         if(ax !== undefined || ay !== undefined){
15859             if(ax !== undefined && ay !== undefined){
15860                 el.setLeftTop(ax, ay);
15861             }else if(ax !== undefined){
15862                 el.setLeft(ax);
15863             }else if(ay !== undefined){
15864                 el.setTop(ay);
15865             }
15866             this.onPosition(ax, ay);
15867             this.fireEvent('move', this, ax, ay);
15868         }
15869         return this;
15870     },
15871
15872     /**
15873      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15874      * This method fires the move event.
15875      * @param {Number} x The new x position
15876      * @param {Number} y The new y position
15877      * @returns {Roo.BoxComponent} this
15878      */
15879     setPagePosition : function(x, y){
15880         this.pageX = x;
15881         this.pageY = y;
15882         if(!this.boxReady){
15883             return;
15884         }
15885         if(x === undefined || y === undefined){ // cannot translate undefined points
15886             return;
15887         }
15888         var p = this.el.translatePoints(x, y);
15889         this.setPosition(p.left, p.top);
15890         return this;
15891     },
15892
15893     // private
15894     onRender : function(ct, position){
15895         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15896         if(this.resizeEl){
15897             this.resizeEl = Roo.get(this.resizeEl);
15898         }
15899         if(this.positionEl){
15900             this.positionEl = Roo.get(this.positionEl);
15901         }
15902     },
15903
15904     // private
15905     afterRender : function(){
15906         Roo.BoxComponent.superclass.afterRender.call(this);
15907         this.boxReady = true;
15908         this.setSize(this.width, this.height);
15909         if(this.x || this.y){
15910             this.setPosition(this.x, this.y);
15911         }
15912         if(this.pageX || this.pageY){
15913             this.setPagePosition(this.pageX, this.pageY);
15914         }
15915     },
15916
15917     /**
15918      * Force the component's size to recalculate based on the underlying element's current height and width.
15919      * @returns {Roo.BoxComponent} this
15920      */
15921     syncSize : function(){
15922         delete this.lastSize;
15923         this.setSize(this.el.getWidth(), this.el.getHeight());
15924         return this;
15925     },
15926
15927     /**
15928      * Called after the component is resized, this method is empty by default but can be implemented by any
15929      * subclass that needs to perform custom logic after a resize occurs.
15930      * @param {Number} adjWidth The box-adjusted width that was set
15931      * @param {Number} adjHeight The box-adjusted height that was set
15932      * @param {Number} rawWidth The width that was originally specified
15933      * @param {Number} rawHeight The height that was originally specified
15934      */
15935     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15936
15937     },
15938
15939     /**
15940      * Called after the component is moved, this method is empty by default but can be implemented by any
15941      * subclass that needs to perform custom logic after a move occurs.
15942      * @param {Number} x The new x position
15943      * @param {Number} y The new y position
15944      */
15945     onPosition : function(x, y){
15946
15947     },
15948
15949     // private
15950     adjustSize : function(w, h){
15951         if(this.autoWidth){
15952             w = 'auto';
15953         }
15954         if(this.autoHeight){
15955             h = 'auto';
15956         }
15957         return {width : w, height: h};
15958     },
15959
15960     // private
15961     adjustPosition : function(x, y){
15962         return {x : x, y: y};
15963     }
15964 });/*
15965  * Original code for Roojs - LGPL
15966  * <script type="text/javascript">
15967  */
15968  
15969 /**
15970  * @class Roo.XComponent
15971  * A delayed Element creator...
15972  * Or a way to group chunks of interface together.
15973  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15974  *  used in conjunction with XComponent.build() it will create an instance of each element,
15975  *  then call addxtype() to build the User interface.
15976  * 
15977  * Mypart.xyx = new Roo.XComponent({
15978
15979     parent : 'Mypart.xyz', // empty == document.element.!!
15980     order : '001',
15981     name : 'xxxx'
15982     region : 'xxxx'
15983     disabled : function() {} 
15984      
15985     tree : function() { // return an tree of xtype declared components
15986         var MODULE = this;
15987         return 
15988         {
15989             xtype : 'NestedLayoutPanel',
15990             // technicall
15991         }
15992      ]
15993  *})
15994  *
15995  *
15996  * It can be used to build a big heiracy, with parent etc.
15997  * or you can just use this to render a single compoent to a dom element
15998  * MYPART.render(Roo.Element | String(id) | dom_element )
15999  *
16000  *
16001  * Usage patterns.
16002  *
16003  * Classic Roo
16004  *
16005  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16006  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16007  *
16008  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16009  *
16010  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16011  * - if mulitple topModules exist, the last one is defined as the top module.
16012  *
16013  * Embeded Roo
16014  * 
16015  * When the top level or multiple modules are to embedded into a existing HTML page,
16016  * the parent element can container '#id' of the element where the module will be drawn.
16017  *
16018  * Bootstrap Roo
16019  *
16020  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16021  * it relies more on a include mechanism, where sub modules are included into an outer page.
16022  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16023  * 
16024  * Bootstrap Roo Included elements
16025  *
16026  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16027  * hence confusing the component builder as it thinks there are multiple top level elements. 
16028  *
16029  * String Over-ride & Translations
16030  *
16031  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16032  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16033  * are needed. @see Roo.XComponent.overlayString  
16034  * 
16035  * 
16036  * 
16037  * @extends Roo.util.Observable
16038  * @constructor
16039  * @param cfg {Object} configuration of component
16040  * 
16041  */
16042 Roo.XComponent = function(cfg) {
16043     Roo.apply(this, cfg);
16044     this.addEvents({ 
16045         /**
16046              * @event built
16047              * Fires when this the componnt is built
16048              * @param {Roo.XComponent} c the component
16049              */
16050         'built' : true
16051         
16052     });
16053     this.region = this.region || 'center'; // default..
16054     Roo.XComponent.register(this);
16055     this.modules = false;
16056     this.el = false; // where the layout goes..
16057     
16058     
16059 }
16060 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16061     /**
16062      * @property el
16063      * The created element (with Roo.factory())
16064      * @type {Roo.Layout}
16065      */
16066     el  : false,
16067     
16068     /**
16069      * @property el
16070      * for BC  - use el in new code
16071      * @type {Roo.Layout}
16072      */
16073     panel : false,
16074     
16075     /**
16076      * @property layout
16077      * for BC  - use el in new code
16078      * @type {Roo.Layout}
16079      */
16080     layout : false,
16081     
16082      /**
16083      * @cfg {Function|boolean} disabled
16084      * If this module is disabled by some rule, return true from the funtion
16085      */
16086     disabled : false,
16087     
16088     /**
16089      * @cfg {String} parent 
16090      * Name of parent element which it get xtype added to..
16091      */
16092     parent: false,
16093     
16094     /**
16095      * @cfg {String} order
16096      * Used to set the order in which elements are created (usefull for multiple tabs)
16097      */
16098     
16099     order : false,
16100     /**
16101      * @cfg {String} name
16102      * String to display while loading.
16103      */
16104     name : false,
16105     /**
16106      * @cfg {String} region
16107      * Region to render component to (defaults to center)
16108      */
16109     region : 'center',
16110     
16111     /**
16112      * @cfg {Array} items
16113      * A single item array - the first element is the root of the tree..
16114      * It's done this way to stay compatible with the Xtype system...
16115      */
16116     items : false,
16117     
16118     /**
16119      * @property _tree
16120      * The method that retuns the tree of parts that make up this compoennt 
16121      * @type {function}
16122      */
16123     _tree  : false,
16124     
16125      /**
16126      * render
16127      * render element to dom or tree
16128      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16129      */
16130     
16131     render : function(el)
16132     {
16133         
16134         el = el || false;
16135         var hp = this.parent ? 1 : 0;
16136         Roo.debug &&  Roo.log(this);
16137         
16138         var tree = this._tree ? this._tree() : this.tree();
16139
16140         
16141         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16142             // if parent is a '#.....' string, then let's use that..
16143             var ename = this.parent.substr(1);
16144             this.parent = false;
16145             Roo.debug && Roo.log(ename);
16146             switch (ename) {
16147                 case 'bootstrap-body':
16148                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16149                         // this is the BorderLayout standard?
16150                        this.parent = { el : true };
16151                        break;
16152                     }
16153                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16154                         // need to insert stuff...
16155                         this.parent =  {
16156                              el : new Roo.bootstrap.layout.Border({
16157                                  el : document.body, 
16158                      
16159                                  center: {
16160                                     titlebar: false,
16161                                     autoScroll:false,
16162                                     closeOnTab: true,
16163                                     tabPosition: 'top',
16164                                       //resizeTabs: true,
16165                                     alwaysShowTabs: true,
16166                                     hideTabs: false
16167                                      //minTabWidth: 140
16168                                  }
16169                              })
16170                         
16171                          };
16172                          break;
16173                     }
16174                          
16175                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16176                         this.parent = { el :  new  Roo.bootstrap.Body() };
16177                         Roo.debug && Roo.log("setting el to doc body");
16178                          
16179                     } else {
16180                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16181                     }
16182                     break;
16183                 case 'bootstrap':
16184                     this.parent = { el : true};
16185                     // fall through
16186                 default:
16187                     el = Roo.get(ename);
16188                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16189                         this.parent = { el : true};
16190                     }
16191                     
16192                     break;
16193             }
16194                 
16195             
16196             if (!el && !this.parent) {
16197                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16198                 return;
16199             }
16200         }
16201         
16202         Roo.debug && Roo.log("EL:");
16203         Roo.debug && Roo.log(el);
16204         Roo.debug && Roo.log("this.parent.el:");
16205         Roo.debug && Roo.log(this.parent.el);
16206         
16207
16208         // altertive root elements ??? - we need a better way to indicate these.
16209         var is_alt = Roo.XComponent.is_alt ||
16210                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16211                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16212                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16213         
16214         
16215         
16216         if (!this.parent && is_alt) {
16217             //el = Roo.get(document.body);
16218             this.parent = { el : true };
16219         }
16220             
16221             
16222         
16223         if (!this.parent) {
16224             
16225             Roo.debug && Roo.log("no parent - creating one");
16226             
16227             el = el ? Roo.get(el) : false;      
16228             
16229             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16230                 
16231                 this.parent =  {
16232                     el : new Roo.bootstrap.layout.Border({
16233                         el: el || document.body,
16234                     
16235                         center: {
16236                             titlebar: false,
16237                             autoScroll:false,
16238                             closeOnTab: true,
16239                             tabPosition: 'top',
16240                              //resizeTabs: true,
16241                             alwaysShowTabs: false,
16242                             hideTabs: true,
16243                             minTabWidth: 140,
16244                             overflow: 'visible'
16245                          }
16246                      })
16247                 };
16248             } else {
16249             
16250                 // it's a top level one..
16251                 this.parent =  {
16252                     el : new Roo.BorderLayout(el || document.body, {
16253                         center: {
16254                             titlebar: false,
16255                             autoScroll:false,
16256                             closeOnTab: true,
16257                             tabPosition: 'top',
16258                              //resizeTabs: true,
16259                             alwaysShowTabs: el && hp? false :  true,
16260                             hideTabs: el || !hp ? true :  false,
16261                             minTabWidth: 140
16262                          }
16263                     })
16264                 };
16265             }
16266         }
16267         
16268         if (!this.parent.el) {
16269                 // probably an old style ctor, which has been disabled.
16270                 return;
16271
16272         }
16273                 // The 'tree' method is  '_tree now' 
16274             
16275         tree.region = tree.region || this.region;
16276         var is_body = false;
16277         if (this.parent.el === true) {
16278             // bootstrap... - body..
16279             if (el) {
16280                 tree.el = el;
16281             }
16282             this.parent.el = Roo.factory(tree);
16283             is_body = true;
16284         }
16285         
16286         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16287         this.fireEvent('built', this);
16288         
16289         this.panel = this.el;
16290         this.layout = this.panel.layout;
16291         this.parentLayout = this.parent.layout  || false;  
16292          
16293     }
16294     
16295 });
16296
16297 Roo.apply(Roo.XComponent, {
16298     /**
16299      * @property  hideProgress
16300      * true to disable the building progress bar.. usefull on single page renders.
16301      * @type Boolean
16302      */
16303     hideProgress : false,
16304     /**
16305      * @property  buildCompleted
16306      * True when the builder has completed building the interface.
16307      * @type Boolean
16308      */
16309     buildCompleted : false,
16310      
16311     /**
16312      * @property  topModule
16313      * the upper most module - uses document.element as it's constructor.
16314      * @type Object
16315      */
16316      
16317     topModule  : false,
16318       
16319     /**
16320      * @property  modules
16321      * array of modules to be created by registration system.
16322      * @type {Array} of Roo.XComponent
16323      */
16324     
16325     modules : [],
16326     /**
16327      * @property  elmodules
16328      * array of modules to be created by which use #ID 
16329      * @type {Array} of Roo.XComponent
16330      */
16331      
16332     elmodules : [],
16333
16334      /**
16335      * @property  is_alt
16336      * Is an alternative Root - normally used by bootstrap or other systems,
16337      *    where the top element in the tree can wrap 'body' 
16338      * @type {boolean}  (default false)
16339      */
16340      
16341     is_alt : false,
16342     /**
16343      * @property  build_from_html
16344      * Build elements from html - used by bootstrap HTML stuff 
16345      *    - this is cleared after build is completed
16346      * @type {boolean}    (default false)
16347      */
16348      
16349     build_from_html : false,
16350     /**
16351      * Register components to be built later.
16352      *
16353      * This solves the following issues
16354      * - Building is not done on page load, but after an authentication process has occured.
16355      * - Interface elements are registered on page load
16356      * - Parent Interface elements may not be loaded before child, so this handles that..
16357      * 
16358      *
16359      * example:
16360      * 
16361      * MyApp.register({
16362           order : '000001',
16363           module : 'Pman.Tab.projectMgr',
16364           region : 'center',
16365           parent : 'Pman.layout',
16366           disabled : false,  // or use a function..
16367         })
16368      
16369      * * @param {Object} details about module
16370      */
16371     register : function(obj) {
16372                 
16373         Roo.XComponent.event.fireEvent('register', obj);
16374         switch(typeof(obj.disabled) ) {
16375                 
16376             case 'undefined':
16377                 break;
16378             
16379             case 'function':
16380                 if ( obj.disabled() ) {
16381                         return;
16382                 }
16383                 break;
16384             
16385             default:
16386                 if (obj.disabled) {
16387                         return;
16388                 }
16389                 break;
16390         }
16391                 
16392         this.modules.push(obj);
16393          
16394     },
16395     /**
16396      * convert a string to an object..
16397      * eg. 'AAA.BBB' -> finds AAA.BBB
16398
16399      */
16400     
16401     toObject : function(str)
16402     {
16403         if (!str || typeof(str) == 'object') {
16404             return str;
16405         }
16406         if (str.substring(0,1) == '#') {
16407             return str;
16408         }
16409
16410         var ar = str.split('.');
16411         var rt, o;
16412         rt = ar.shift();
16413             /** eval:var:o */
16414         try {
16415             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16416         } catch (e) {
16417             throw "Module not found : " + str;
16418         }
16419         
16420         if (o === false) {
16421             throw "Module not found : " + str;
16422         }
16423         Roo.each(ar, function(e) {
16424             if (typeof(o[e]) == 'undefined') {
16425                 throw "Module not found : " + str;
16426             }
16427             o = o[e];
16428         });
16429         
16430         return o;
16431         
16432     },
16433     
16434     
16435     /**
16436      * move modules into their correct place in the tree..
16437      * 
16438      */
16439     preBuild : function ()
16440     {
16441         var _t = this;
16442         Roo.each(this.modules , function (obj)
16443         {
16444             Roo.XComponent.event.fireEvent('beforebuild', obj);
16445             
16446             var opar = obj.parent;
16447             try { 
16448                 obj.parent = this.toObject(opar);
16449             } catch(e) {
16450                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16451                 return;
16452             }
16453             
16454             if (!obj.parent) {
16455                 Roo.debug && Roo.log("GOT top level module");
16456                 Roo.debug && Roo.log(obj);
16457                 obj.modules = new Roo.util.MixedCollection(false, 
16458                     function(o) { return o.order + '' }
16459                 );
16460                 this.topModule = obj;
16461                 return;
16462             }
16463                         // parent is a string (usually a dom element name..)
16464             if (typeof(obj.parent) == 'string') {
16465                 this.elmodules.push(obj);
16466                 return;
16467             }
16468             if (obj.parent.constructor != Roo.XComponent) {
16469                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16470             }
16471             if (!obj.parent.modules) {
16472                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16473                     function(o) { return o.order + '' }
16474                 );
16475             }
16476             if (obj.parent.disabled) {
16477                 obj.disabled = true;
16478             }
16479             obj.parent.modules.add(obj);
16480         }, this);
16481     },
16482     
16483      /**
16484      * make a list of modules to build.
16485      * @return {Array} list of modules. 
16486      */ 
16487     
16488     buildOrder : function()
16489     {
16490         var _this = this;
16491         var cmp = function(a,b) {   
16492             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16493         };
16494         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16495             throw "No top level modules to build";
16496         }
16497         
16498         // make a flat list in order of modules to build.
16499         var mods = this.topModule ? [ this.topModule ] : [];
16500                 
16501         
16502         // elmodules (is a list of DOM based modules )
16503         Roo.each(this.elmodules, function(e) {
16504             mods.push(e);
16505             if (!this.topModule &&
16506                 typeof(e.parent) == 'string' &&
16507                 e.parent.substring(0,1) == '#' &&
16508                 Roo.get(e.parent.substr(1))
16509                ) {
16510                 
16511                 _this.topModule = e;
16512             }
16513             
16514         });
16515
16516         
16517         // add modules to their parents..
16518         var addMod = function(m) {
16519             Roo.debug && Roo.log("build Order: add: " + m.name);
16520                 
16521             mods.push(m);
16522             if (m.modules && !m.disabled) {
16523                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16524                 m.modules.keySort('ASC',  cmp );
16525                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16526     
16527                 m.modules.each(addMod);
16528             } else {
16529                 Roo.debug && Roo.log("build Order: no child modules");
16530             }
16531             // not sure if this is used any more..
16532             if (m.finalize) {
16533                 m.finalize.name = m.name + " (clean up) ";
16534                 mods.push(m.finalize);
16535             }
16536             
16537         }
16538         if (this.topModule && this.topModule.modules) { 
16539             this.topModule.modules.keySort('ASC',  cmp );
16540             this.topModule.modules.each(addMod);
16541         } 
16542         return mods;
16543     },
16544     
16545      /**
16546      * Build the registered modules.
16547      * @param {Object} parent element.
16548      * @param {Function} optional method to call after module has been added.
16549      * 
16550      */ 
16551    
16552     build : function(opts) 
16553     {
16554         
16555         if (typeof(opts) != 'undefined') {
16556             Roo.apply(this,opts);
16557         }
16558         
16559         this.preBuild();
16560         var mods = this.buildOrder();
16561       
16562         //this.allmods = mods;
16563         //Roo.debug && Roo.log(mods);
16564         //return;
16565         if (!mods.length) { // should not happen
16566             throw "NO modules!!!";
16567         }
16568         
16569         
16570         var msg = "Building Interface...";
16571         // flash it up as modal - so we store the mask!?
16572         if (!this.hideProgress && Roo.MessageBox) {
16573             Roo.MessageBox.show({ title: 'loading' });
16574             Roo.MessageBox.show({
16575                title: "Please wait...",
16576                msg: msg,
16577                width:450,
16578                progress:true,
16579                closable:false,
16580                modal: false
16581               
16582             });
16583         }
16584         var total = mods.length;
16585         
16586         var _this = this;
16587         var progressRun = function() {
16588             if (!mods.length) {
16589                 Roo.debug && Roo.log('hide?');
16590                 if (!this.hideProgress && Roo.MessageBox) {
16591                     Roo.MessageBox.hide();
16592                 }
16593                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16594                 
16595                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16596                 
16597                 // THE END...
16598                 return false;   
16599             }
16600             
16601             var m = mods.shift();
16602             
16603             
16604             Roo.debug && Roo.log(m);
16605             // not sure if this is supported any more.. - modules that are are just function
16606             if (typeof(m) == 'function') { 
16607                 m.call(this);
16608                 return progressRun.defer(10, _this);
16609             } 
16610             
16611             
16612             msg = "Building Interface " + (total  - mods.length) + 
16613                     " of " + total + 
16614                     (m.name ? (' - ' + m.name) : '');
16615                         Roo.debug && Roo.log(msg);
16616             if (!_this.hideProgress &&  Roo.MessageBox) { 
16617                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16618             }
16619             
16620          
16621             // is the module disabled?
16622             var disabled = (typeof(m.disabled) == 'function') ?
16623                 m.disabled.call(m.module.disabled) : m.disabled;    
16624             
16625             
16626             if (disabled) {
16627                 return progressRun(); // we do not update the display!
16628             }
16629             
16630             // now build 
16631             
16632                         
16633                         
16634             m.render();
16635             // it's 10 on top level, and 1 on others??? why...
16636             return progressRun.defer(10, _this);
16637              
16638         }
16639         progressRun.defer(1, _this);
16640      
16641         
16642         
16643     },
16644     /**
16645      * Overlay a set of modified strings onto a component
16646      * This is dependant on our builder exporting the strings and 'named strings' elements.
16647      * 
16648      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16649      * @param {Object} associative array of 'named' string and it's new value.
16650      * 
16651      */
16652         overlayStrings : function( component, strings )
16653     {
16654         if (typeof(component['_named_strings']) == 'undefined') {
16655             throw "ERROR: component does not have _named_strings";
16656         }
16657         for ( var k in strings ) {
16658             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16659             if (md !== false) {
16660                 component['_strings'][md] = strings[k];
16661             } else {
16662                 Roo.log('could not find named string: ' + k + ' in');
16663                 Roo.log(component);
16664             }
16665             
16666         }
16667         
16668     },
16669     
16670         
16671         /**
16672          * Event Object.
16673          *
16674          *
16675          */
16676         event: false, 
16677     /**
16678          * wrapper for event.on - aliased later..  
16679          * Typically use to register a event handler for register:
16680          *
16681          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16682          *
16683          */
16684     on : false
16685    
16686     
16687     
16688 });
16689
16690 Roo.XComponent.event = new Roo.util.Observable({
16691                 events : { 
16692                         /**
16693                          * @event register
16694                          * Fires when an Component is registered,
16695                          * set the disable property on the Component to stop registration.
16696                          * @param {Roo.XComponent} c the component being registerd.
16697                          * 
16698                          */
16699                         'register' : true,
16700             /**
16701                          * @event beforebuild
16702                          * Fires before each Component is built
16703                          * can be used to apply permissions.
16704                          * @param {Roo.XComponent} c the component being registerd.
16705                          * 
16706                          */
16707                         'beforebuild' : true,
16708                         /**
16709                          * @event buildcomplete
16710                          * Fires on the top level element when all elements have been built
16711                          * @param {Roo.XComponent} the top level component.
16712                          */
16713                         'buildcomplete' : true
16714                         
16715                 }
16716 });
16717
16718 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16719  //
16720  /**
16721  * marked - a markdown parser
16722  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16723  * https://github.com/chjj/marked
16724  */
16725
16726
16727 /**
16728  *
16729  * Roo.Markdown - is a very crude wrapper around marked..
16730  *
16731  * usage:
16732  * 
16733  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16734  * 
16735  * Note: move the sample code to the bottom of this
16736  * file before uncommenting it.
16737  *
16738  */
16739
16740 Roo.Markdown = {};
16741 Roo.Markdown.toHtml = function(text) {
16742     
16743     var c = new Roo.Markdown.marked.setOptions({
16744             renderer: new Roo.Markdown.marked.Renderer(),
16745             gfm: true,
16746             tables: true,
16747             breaks: false,
16748             pedantic: false,
16749             sanitize: false,
16750             smartLists: true,
16751             smartypants: false
16752           });
16753     // A FEW HACKS!!?
16754     
16755     text = text.replace(/\\\n/g,' ');
16756     return Roo.Markdown.marked(text);
16757 };
16758 //
16759 // converter
16760 //
16761 // Wraps all "globals" so that the only thing
16762 // exposed is makeHtml().
16763 //
16764 (function() {
16765     
16766     /**
16767      * Block-Level Grammar
16768      */
16769     
16770     var block = {
16771       newline: /^\n+/,
16772       code: /^( {4}[^\n]+\n*)+/,
16773       fences: noop,
16774       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16775       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16776       nptable: noop,
16777       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16778       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16779       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16780       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16781       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16782       table: noop,
16783       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16784       text: /^[^\n]+/
16785     };
16786     
16787     block.bullet = /(?:[*+-]|\d+\.)/;
16788     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16789     block.item = replace(block.item, 'gm')
16790       (/bull/g, block.bullet)
16791       ();
16792     
16793     block.list = replace(block.list)
16794       (/bull/g, block.bullet)
16795       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16796       ('def', '\\n+(?=' + block.def.source + ')')
16797       ();
16798     
16799     block.blockquote = replace(block.blockquote)
16800       ('def', block.def)
16801       ();
16802     
16803     block._tag = '(?!(?:'
16804       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16805       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16806       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16807     
16808     block.html = replace(block.html)
16809       ('comment', /<!--[\s\S]*?-->/)
16810       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16811       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16812       (/tag/g, block._tag)
16813       ();
16814     
16815     block.paragraph = replace(block.paragraph)
16816       ('hr', block.hr)
16817       ('heading', block.heading)
16818       ('lheading', block.lheading)
16819       ('blockquote', block.blockquote)
16820       ('tag', '<' + block._tag)
16821       ('def', block.def)
16822       ();
16823     
16824     /**
16825      * Normal Block Grammar
16826      */
16827     
16828     block.normal = merge({}, block);
16829     
16830     /**
16831      * GFM Block Grammar
16832      */
16833     
16834     block.gfm = merge({}, block.normal, {
16835       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16836       paragraph: /^/,
16837       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16838     });
16839     
16840     block.gfm.paragraph = replace(block.paragraph)
16841       ('(?!', '(?!'
16842         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16843         + block.list.source.replace('\\1', '\\3') + '|')
16844       ();
16845     
16846     /**
16847      * GFM + Tables Block Grammar
16848      */
16849     
16850     block.tables = merge({}, block.gfm, {
16851       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16852       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16853     });
16854     
16855     /**
16856      * Block Lexer
16857      */
16858     
16859     function Lexer(options) {
16860       this.tokens = [];
16861       this.tokens.links = {};
16862       this.options = options || marked.defaults;
16863       this.rules = block.normal;
16864     
16865       if (this.options.gfm) {
16866         if (this.options.tables) {
16867           this.rules = block.tables;
16868         } else {
16869           this.rules = block.gfm;
16870         }
16871       }
16872     }
16873     
16874     /**
16875      * Expose Block Rules
16876      */
16877     
16878     Lexer.rules = block;
16879     
16880     /**
16881      * Static Lex Method
16882      */
16883     
16884     Lexer.lex = function(src, options) {
16885       var lexer = new Lexer(options);
16886       return lexer.lex(src);
16887     };
16888     
16889     /**
16890      * Preprocessing
16891      */
16892     
16893     Lexer.prototype.lex = function(src) {
16894       src = src
16895         .replace(/\r\n|\r/g, '\n')
16896         .replace(/\t/g, '    ')
16897         .replace(/\u00a0/g, ' ')
16898         .replace(/\u2424/g, '\n');
16899     
16900       return this.token(src, true);
16901     };
16902     
16903     /**
16904      * Lexing
16905      */
16906     
16907     Lexer.prototype.token = function(src, top, bq) {
16908       var src = src.replace(/^ +$/gm, '')
16909         , next
16910         , loose
16911         , cap
16912         , bull
16913         , b
16914         , item
16915         , space
16916         , i
16917         , l;
16918     
16919       while (src) {
16920         // newline
16921         if (cap = this.rules.newline.exec(src)) {
16922           src = src.substring(cap[0].length);
16923           if (cap[0].length > 1) {
16924             this.tokens.push({
16925               type: 'space'
16926             });
16927           }
16928         }
16929     
16930         // code
16931         if (cap = this.rules.code.exec(src)) {
16932           src = src.substring(cap[0].length);
16933           cap = cap[0].replace(/^ {4}/gm, '');
16934           this.tokens.push({
16935             type: 'code',
16936             text: !this.options.pedantic
16937               ? cap.replace(/\n+$/, '')
16938               : cap
16939           });
16940           continue;
16941         }
16942     
16943         // fences (gfm)
16944         if (cap = this.rules.fences.exec(src)) {
16945           src = src.substring(cap[0].length);
16946           this.tokens.push({
16947             type: 'code',
16948             lang: cap[2],
16949             text: cap[3] || ''
16950           });
16951           continue;
16952         }
16953     
16954         // heading
16955         if (cap = this.rules.heading.exec(src)) {
16956           src = src.substring(cap[0].length);
16957           this.tokens.push({
16958             type: 'heading',
16959             depth: cap[1].length,
16960             text: cap[2]
16961           });
16962           continue;
16963         }
16964     
16965         // table no leading pipe (gfm)
16966         if (top && (cap = this.rules.nptable.exec(src))) {
16967           src = src.substring(cap[0].length);
16968     
16969           item = {
16970             type: 'table',
16971             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16972             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16973             cells: cap[3].replace(/\n$/, '').split('\n')
16974           };
16975     
16976           for (i = 0; i < item.align.length; i++) {
16977             if (/^ *-+: *$/.test(item.align[i])) {
16978               item.align[i] = 'right';
16979             } else if (/^ *:-+: *$/.test(item.align[i])) {
16980               item.align[i] = 'center';
16981             } else if (/^ *:-+ *$/.test(item.align[i])) {
16982               item.align[i] = 'left';
16983             } else {
16984               item.align[i] = null;
16985             }
16986           }
16987     
16988           for (i = 0; i < item.cells.length; i++) {
16989             item.cells[i] = item.cells[i].split(/ *\| */);
16990           }
16991     
16992           this.tokens.push(item);
16993     
16994           continue;
16995         }
16996     
16997         // lheading
16998         if (cap = this.rules.lheading.exec(src)) {
16999           src = src.substring(cap[0].length);
17000           this.tokens.push({
17001             type: 'heading',
17002             depth: cap[2] === '=' ? 1 : 2,
17003             text: cap[1]
17004           });
17005           continue;
17006         }
17007     
17008         // hr
17009         if (cap = this.rules.hr.exec(src)) {
17010           src = src.substring(cap[0].length);
17011           this.tokens.push({
17012             type: 'hr'
17013           });
17014           continue;
17015         }
17016     
17017         // blockquote
17018         if (cap = this.rules.blockquote.exec(src)) {
17019           src = src.substring(cap[0].length);
17020     
17021           this.tokens.push({
17022             type: 'blockquote_start'
17023           });
17024     
17025           cap = cap[0].replace(/^ *> ?/gm, '');
17026     
17027           // Pass `top` to keep the current
17028           // "toplevel" state. This is exactly
17029           // how markdown.pl works.
17030           this.token(cap, top, true);
17031     
17032           this.tokens.push({
17033             type: 'blockquote_end'
17034           });
17035     
17036           continue;
17037         }
17038     
17039         // list
17040         if (cap = this.rules.list.exec(src)) {
17041           src = src.substring(cap[0].length);
17042           bull = cap[2];
17043     
17044           this.tokens.push({
17045             type: 'list_start',
17046             ordered: bull.length > 1
17047           });
17048     
17049           // Get each top-level item.
17050           cap = cap[0].match(this.rules.item);
17051     
17052           next = false;
17053           l = cap.length;
17054           i = 0;
17055     
17056           for (; i < l; i++) {
17057             item = cap[i];
17058     
17059             // Remove the list item's bullet
17060             // so it is seen as the next token.
17061             space = item.length;
17062             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17063     
17064             // Outdent whatever the
17065             // list item contains. Hacky.
17066             if (~item.indexOf('\n ')) {
17067               space -= item.length;
17068               item = !this.options.pedantic
17069                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17070                 : item.replace(/^ {1,4}/gm, '');
17071             }
17072     
17073             // Determine whether the next list item belongs here.
17074             // Backpedal if it does not belong in this list.
17075             if (this.options.smartLists && i !== l - 1) {
17076               b = block.bullet.exec(cap[i + 1])[0];
17077               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17078                 src = cap.slice(i + 1).join('\n') + src;
17079                 i = l - 1;
17080               }
17081             }
17082     
17083             // Determine whether item is loose or not.
17084             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17085             // for discount behavior.
17086             loose = next || /\n\n(?!\s*$)/.test(item);
17087             if (i !== l - 1) {
17088               next = item.charAt(item.length - 1) === '\n';
17089               if (!loose) { loose = next; }
17090             }
17091     
17092             this.tokens.push({
17093               type: loose
17094                 ? 'loose_item_start'
17095                 : 'list_item_start'
17096             });
17097     
17098             // Recurse.
17099             this.token(item, false, bq);
17100     
17101             this.tokens.push({
17102               type: 'list_item_end'
17103             });
17104           }
17105     
17106           this.tokens.push({
17107             type: 'list_end'
17108           });
17109     
17110           continue;
17111         }
17112     
17113         // html
17114         if (cap = this.rules.html.exec(src)) {
17115           src = src.substring(cap[0].length);
17116           this.tokens.push({
17117             type: this.options.sanitize
17118               ? 'paragraph'
17119               : 'html',
17120             pre: !this.options.sanitizer
17121               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17122             text: cap[0]
17123           });
17124           continue;
17125         }
17126     
17127         // def
17128         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17129           src = src.substring(cap[0].length);
17130           this.tokens.links[cap[1].toLowerCase()] = {
17131             href: cap[2],
17132             title: cap[3]
17133           };
17134           continue;
17135         }
17136     
17137         // table (gfm)
17138         if (top && (cap = this.rules.table.exec(src))) {
17139           src = src.substring(cap[0].length);
17140     
17141           item = {
17142             type: 'table',
17143             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17144             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17145             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17146           };
17147     
17148           for (i = 0; i < item.align.length; i++) {
17149             if (/^ *-+: *$/.test(item.align[i])) {
17150               item.align[i] = 'right';
17151             } else if (/^ *:-+: *$/.test(item.align[i])) {
17152               item.align[i] = 'center';
17153             } else if (/^ *:-+ *$/.test(item.align[i])) {
17154               item.align[i] = 'left';
17155             } else {
17156               item.align[i] = null;
17157             }
17158           }
17159     
17160           for (i = 0; i < item.cells.length; i++) {
17161             item.cells[i] = item.cells[i]
17162               .replace(/^ *\| *| *\| *$/g, '')
17163               .split(/ *\| */);
17164           }
17165     
17166           this.tokens.push(item);
17167     
17168           continue;
17169         }
17170     
17171         // top-level paragraph
17172         if (top && (cap = this.rules.paragraph.exec(src))) {
17173           src = src.substring(cap[0].length);
17174           this.tokens.push({
17175             type: 'paragraph',
17176             text: cap[1].charAt(cap[1].length - 1) === '\n'
17177               ? cap[1].slice(0, -1)
17178               : cap[1]
17179           });
17180           continue;
17181         }
17182     
17183         // text
17184         if (cap = this.rules.text.exec(src)) {
17185           // Top-level should never reach here.
17186           src = src.substring(cap[0].length);
17187           this.tokens.push({
17188             type: 'text',
17189             text: cap[0]
17190           });
17191           continue;
17192         }
17193     
17194         if (src) {
17195           throw new
17196             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17197         }
17198       }
17199     
17200       return this.tokens;
17201     };
17202     
17203     /**
17204      * Inline-Level Grammar
17205      */
17206     
17207     var inline = {
17208       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17209       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17210       url: noop,
17211       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17212       link: /^!?\[(inside)\]\(href\)/,
17213       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17214       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17215       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17216       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17217       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17218       br: /^ {2,}\n(?!\s*$)/,
17219       del: noop,
17220       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17221     };
17222     
17223     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17224     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17225     
17226     inline.link = replace(inline.link)
17227       ('inside', inline._inside)
17228       ('href', inline._href)
17229       ();
17230     
17231     inline.reflink = replace(inline.reflink)
17232       ('inside', inline._inside)
17233       ();
17234     
17235     /**
17236      * Normal Inline Grammar
17237      */
17238     
17239     inline.normal = merge({}, inline);
17240     
17241     /**
17242      * Pedantic Inline Grammar
17243      */
17244     
17245     inline.pedantic = merge({}, inline.normal, {
17246       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17247       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17248     });
17249     
17250     /**
17251      * GFM Inline Grammar
17252      */
17253     
17254     inline.gfm = merge({}, inline.normal, {
17255       escape: replace(inline.escape)('])', '~|])')(),
17256       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17257       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17258       text: replace(inline.text)
17259         (']|', '~]|')
17260         ('|', '|https?://|')
17261         ()
17262     });
17263     
17264     /**
17265      * GFM + Line Breaks Inline Grammar
17266      */
17267     
17268     inline.breaks = merge({}, inline.gfm, {
17269       br: replace(inline.br)('{2,}', '*')(),
17270       text: replace(inline.gfm.text)('{2,}', '*')()
17271     });
17272     
17273     /**
17274      * Inline Lexer & Compiler
17275      */
17276     
17277     function InlineLexer(links, options) {
17278       this.options = options || marked.defaults;
17279       this.links = links;
17280       this.rules = inline.normal;
17281       this.renderer = this.options.renderer || new Renderer;
17282       this.renderer.options = this.options;
17283     
17284       if (!this.links) {
17285         throw new
17286           Error('Tokens array requires a `links` property.');
17287       }
17288     
17289       if (this.options.gfm) {
17290         if (this.options.breaks) {
17291           this.rules = inline.breaks;
17292         } else {
17293           this.rules = inline.gfm;
17294         }
17295       } else if (this.options.pedantic) {
17296         this.rules = inline.pedantic;
17297       }
17298     }
17299     
17300     /**
17301      * Expose Inline Rules
17302      */
17303     
17304     InlineLexer.rules = inline;
17305     
17306     /**
17307      * Static Lexing/Compiling Method
17308      */
17309     
17310     InlineLexer.output = function(src, links, options) {
17311       var inline = new InlineLexer(links, options);
17312       return inline.output(src);
17313     };
17314     
17315     /**
17316      * Lexing/Compiling
17317      */
17318     
17319     InlineLexer.prototype.output = function(src) {
17320       var out = ''
17321         , link
17322         , text
17323         , href
17324         , cap;
17325     
17326       while (src) {
17327         // escape
17328         if (cap = this.rules.escape.exec(src)) {
17329           src = src.substring(cap[0].length);
17330           out += cap[1];
17331           continue;
17332         }
17333     
17334         // autolink
17335         if (cap = this.rules.autolink.exec(src)) {
17336           src = src.substring(cap[0].length);
17337           if (cap[2] === '@') {
17338             text = cap[1].charAt(6) === ':'
17339               ? this.mangle(cap[1].substring(7))
17340               : this.mangle(cap[1]);
17341             href = this.mangle('mailto:') + text;
17342           } else {
17343             text = escape(cap[1]);
17344             href = text;
17345           }
17346           out += this.renderer.link(href, null, text);
17347           continue;
17348         }
17349     
17350         // url (gfm)
17351         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17352           src = src.substring(cap[0].length);
17353           text = escape(cap[1]);
17354           href = text;
17355           out += this.renderer.link(href, null, text);
17356           continue;
17357         }
17358     
17359         // tag
17360         if (cap = this.rules.tag.exec(src)) {
17361           if (!this.inLink && /^<a /i.test(cap[0])) {
17362             this.inLink = true;
17363           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17364             this.inLink = false;
17365           }
17366           src = src.substring(cap[0].length);
17367           out += this.options.sanitize
17368             ? this.options.sanitizer
17369               ? this.options.sanitizer(cap[0])
17370               : escape(cap[0])
17371             : cap[0];
17372           continue;
17373         }
17374     
17375         // link
17376         if (cap = this.rules.link.exec(src)) {
17377           src = src.substring(cap[0].length);
17378           this.inLink = true;
17379           out += this.outputLink(cap, {
17380             href: cap[2],
17381             title: cap[3]
17382           });
17383           this.inLink = false;
17384           continue;
17385         }
17386     
17387         // reflink, nolink
17388         if ((cap = this.rules.reflink.exec(src))
17389             || (cap = this.rules.nolink.exec(src))) {
17390           src = src.substring(cap[0].length);
17391           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17392           link = this.links[link.toLowerCase()];
17393           if (!link || !link.href) {
17394             out += cap[0].charAt(0);
17395             src = cap[0].substring(1) + src;
17396             continue;
17397           }
17398           this.inLink = true;
17399           out += this.outputLink(cap, link);
17400           this.inLink = false;
17401           continue;
17402         }
17403     
17404         // strong
17405         if (cap = this.rules.strong.exec(src)) {
17406           src = src.substring(cap[0].length);
17407           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17408           continue;
17409         }
17410     
17411         // em
17412         if (cap = this.rules.em.exec(src)) {
17413           src = src.substring(cap[0].length);
17414           out += this.renderer.em(this.output(cap[2] || cap[1]));
17415           continue;
17416         }
17417     
17418         // code
17419         if (cap = this.rules.code.exec(src)) {
17420           src = src.substring(cap[0].length);
17421           out += this.renderer.codespan(escape(cap[2], true));
17422           continue;
17423         }
17424     
17425         // br
17426         if (cap = this.rules.br.exec(src)) {
17427           src = src.substring(cap[0].length);
17428           out += this.renderer.br();
17429           continue;
17430         }
17431     
17432         // del (gfm)
17433         if (cap = this.rules.del.exec(src)) {
17434           src = src.substring(cap[0].length);
17435           out += this.renderer.del(this.output(cap[1]));
17436           continue;
17437         }
17438     
17439         // text
17440         if (cap = this.rules.text.exec(src)) {
17441           src = src.substring(cap[0].length);
17442           out += this.renderer.text(escape(this.smartypants(cap[0])));
17443           continue;
17444         }
17445     
17446         if (src) {
17447           throw new
17448             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17449         }
17450       }
17451     
17452       return out;
17453     };
17454     
17455     /**
17456      * Compile Link
17457      */
17458     
17459     InlineLexer.prototype.outputLink = function(cap, link) {
17460       var href = escape(link.href)
17461         , title = link.title ? escape(link.title) : null;
17462     
17463       return cap[0].charAt(0) !== '!'
17464         ? this.renderer.link(href, title, this.output(cap[1]))
17465         : this.renderer.image(href, title, escape(cap[1]));
17466     };
17467     
17468     /**
17469      * Smartypants Transformations
17470      */
17471     
17472     InlineLexer.prototype.smartypants = function(text) {
17473       if (!this.options.smartypants)  { return text; }
17474       return text
17475         // em-dashes
17476         .replace(/---/g, '\u2014')
17477         // en-dashes
17478         .replace(/--/g, '\u2013')
17479         // opening singles
17480         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17481         // closing singles & apostrophes
17482         .replace(/'/g, '\u2019')
17483         // opening doubles
17484         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17485         // closing doubles
17486         .replace(/"/g, '\u201d')
17487         // ellipses
17488         .replace(/\.{3}/g, '\u2026');
17489     };
17490     
17491     /**
17492      * Mangle Links
17493      */
17494     
17495     InlineLexer.prototype.mangle = function(text) {
17496       if (!this.options.mangle) { return text; }
17497       var out = ''
17498         , l = text.length
17499         , i = 0
17500         , ch;
17501     
17502       for (; i < l; i++) {
17503         ch = text.charCodeAt(i);
17504         if (Math.random() > 0.5) {
17505           ch = 'x' + ch.toString(16);
17506         }
17507         out += '&#' + ch + ';';
17508       }
17509     
17510       return out;
17511     };
17512     
17513     /**
17514      * Renderer
17515      */
17516     
17517     function Renderer(options) {
17518       this.options = options || {};
17519     }
17520     
17521     Renderer.prototype.code = function(code, lang, escaped) {
17522       if (this.options.highlight) {
17523         var out = this.options.highlight(code, lang);
17524         if (out != null && out !== code) {
17525           escaped = true;
17526           code = out;
17527         }
17528       } else {
17529             // hack!!! - it's already escapeD?
17530             escaped = true;
17531       }
17532     
17533       if (!lang) {
17534         return '<pre><code>'
17535           + (escaped ? code : escape(code, true))
17536           + '\n</code></pre>';
17537       }
17538     
17539       return '<pre><code class="'
17540         + this.options.langPrefix
17541         + escape(lang, true)
17542         + '">'
17543         + (escaped ? code : escape(code, true))
17544         + '\n</code></pre>\n';
17545     };
17546     
17547     Renderer.prototype.blockquote = function(quote) {
17548       return '<blockquote>\n' + quote + '</blockquote>\n';
17549     };
17550     
17551     Renderer.prototype.html = function(html) {
17552       return html;
17553     };
17554     
17555     Renderer.prototype.heading = function(text, level, raw) {
17556       return '<h'
17557         + level
17558         + ' id="'
17559         + this.options.headerPrefix
17560         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17561         + '">'
17562         + text
17563         + '</h'
17564         + level
17565         + '>\n';
17566     };
17567     
17568     Renderer.prototype.hr = function() {
17569       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17570     };
17571     
17572     Renderer.prototype.list = function(body, ordered) {
17573       var type = ordered ? 'ol' : 'ul';
17574       return '<' + type + '>\n' + body + '</' + type + '>\n';
17575     };
17576     
17577     Renderer.prototype.listitem = function(text) {
17578       return '<li>' + text + '</li>\n';
17579     };
17580     
17581     Renderer.prototype.paragraph = function(text) {
17582       return '<p>' + text + '</p>\n';
17583     };
17584     
17585     Renderer.prototype.table = function(header, body) {
17586       return '<table class="table table-striped">\n'
17587         + '<thead>\n'
17588         + header
17589         + '</thead>\n'
17590         + '<tbody>\n'
17591         + body
17592         + '</tbody>\n'
17593         + '</table>\n';
17594     };
17595     
17596     Renderer.prototype.tablerow = function(content) {
17597       return '<tr>\n' + content + '</tr>\n';
17598     };
17599     
17600     Renderer.prototype.tablecell = function(content, flags) {
17601       var type = flags.header ? 'th' : 'td';
17602       var tag = flags.align
17603         ? '<' + type + ' style="text-align:' + flags.align + '">'
17604         : '<' + type + '>';
17605       return tag + content + '</' + type + '>\n';
17606     };
17607     
17608     // span level renderer
17609     Renderer.prototype.strong = function(text) {
17610       return '<strong>' + text + '</strong>';
17611     };
17612     
17613     Renderer.prototype.em = function(text) {
17614       return '<em>' + text + '</em>';
17615     };
17616     
17617     Renderer.prototype.codespan = function(text) {
17618       return '<code>' + text + '</code>';
17619     };
17620     
17621     Renderer.prototype.br = function() {
17622       return this.options.xhtml ? '<br/>' : '<br>';
17623     };
17624     
17625     Renderer.prototype.del = function(text) {
17626       return '<del>' + text + '</del>';
17627     };
17628     
17629     Renderer.prototype.link = function(href, title, text) {
17630       if (this.options.sanitize) {
17631         try {
17632           var prot = decodeURIComponent(unescape(href))
17633             .replace(/[^\w:]/g, '')
17634             .toLowerCase();
17635         } catch (e) {
17636           return '';
17637         }
17638         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17639           return '';
17640         }
17641       }
17642       var out = '<a href="' + href + '"';
17643       if (title) {
17644         out += ' title="' + title + '"';
17645       }
17646       out += '>' + text + '</a>';
17647       return out;
17648     };
17649     
17650     Renderer.prototype.image = function(href, title, text) {
17651       var out = '<img src="' + href + '" alt="' + text + '"';
17652       if (title) {
17653         out += ' title="' + title + '"';
17654       }
17655       out += this.options.xhtml ? '/>' : '>';
17656       return out;
17657     };
17658     
17659     Renderer.prototype.text = function(text) {
17660       return text;
17661     };
17662     
17663     /**
17664      * Parsing & Compiling
17665      */
17666     
17667     function Parser(options) {
17668       this.tokens = [];
17669       this.token = null;
17670       this.options = options || marked.defaults;
17671       this.options.renderer = this.options.renderer || new Renderer;
17672       this.renderer = this.options.renderer;
17673       this.renderer.options = this.options;
17674     }
17675     
17676     /**
17677      * Static Parse Method
17678      */
17679     
17680     Parser.parse = function(src, options, renderer) {
17681       var parser = new Parser(options, renderer);
17682       return parser.parse(src);
17683     };
17684     
17685     /**
17686      * Parse Loop
17687      */
17688     
17689     Parser.prototype.parse = function(src) {
17690       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17691       this.tokens = src.reverse();
17692     
17693       var out = '';
17694       while (this.next()) {
17695         out += this.tok();
17696       }
17697     
17698       return out;
17699     };
17700     
17701     /**
17702      * Next Token
17703      */
17704     
17705     Parser.prototype.next = function() {
17706       return this.token = this.tokens.pop();
17707     };
17708     
17709     /**
17710      * Preview Next Token
17711      */
17712     
17713     Parser.prototype.peek = function() {
17714       return this.tokens[this.tokens.length - 1] || 0;
17715     };
17716     
17717     /**
17718      * Parse Text Tokens
17719      */
17720     
17721     Parser.prototype.parseText = function() {
17722       var body = this.token.text;
17723     
17724       while (this.peek().type === 'text') {
17725         body += '\n' + this.next().text;
17726       }
17727     
17728       return this.inline.output(body);
17729     };
17730     
17731     /**
17732      * Parse Current Token
17733      */
17734     
17735     Parser.prototype.tok = function() {
17736       switch (this.token.type) {
17737         case 'space': {
17738           return '';
17739         }
17740         case 'hr': {
17741           return this.renderer.hr();
17742         }
17743         case 'heading': {
17744           return this.renderer.heading(
17745             this.inline.output(this.token.text),
17746             this.token.depth,
17747             this.token.text);
17748         }
17749         case 'code': {
17750           return this.renderer.code(this.token.text,
17751             this.token.lang,
17752             this.token.escaped);
17753         }
17754         case 'table': {
17755           var header = ''
17756             , body = ''
17757             , i
17758             , row
17759             , cell
17760             , flags
17761             , j;
17762     
17763           // header
17764           cell = '';
17765           for (i = 0; i < this.token.header.length; i++) {
17766             flags = { header: true, align: this.token.align[i] };
17767             cell += this.renderer.tablecell(
17768               this.inline.output(this.token.header[i]),
17769               { header: true, align: this.token.align[i] }
17770             );
17771           }
17772           header += this.renderer.tablerow(cell);
17773     
17774           for (i = 0; i < this.token.cells.length; i++) {
17775             row = this.token.cells[i];
17776     
17777             cell = '';
17778             for (j = 0; j < row.length; j++) {
17779               cell += this.renderer.tablecell(
17780                 this.inline.output(row[j]),
17781                 { header: false, align: this.token.align[j] }
17782               );
17783             }
17784     
17785             body += this.renderer.tablerow(cell);
17786           }
17787           return this.renderer.table(header, body);
17788         }
17789         case 'blockquote_start': {
17790           var body = '';
17791     
17792           while (this.next().type !== 'blockquote_end') {
17793             body += this.tok();
17794           }
17795     
17796           return this.renderer.blockquote(body);
17797         }
17798         case 'list_start': {
17799           var body = ''
17800             , ordered = this.token.ordered;
17801     
17802           while (this.next().type !== 'list_end') {
17803             body += this.tok();
17804           }
17805     
17806           return this.renderer.list(body, ordered);
17807         }
17808         case 'list_item_start': {
17809           var body = '';
17810     
17811           while (this.next().type !== 'list_item_end') {
17812             body += this.token.type === 'text'
17813               ? this.parseText()
17814               : this.tok();
17815           }
17816     
17817           return this.renderer.listitem(body);
17818         }
17819         case 'loose_item_start': {
17820           var body = '';
17821     
17822           while (this.next().type !== 'list_item_end') {
17823             body += this.tok();
17824           }
17825     
17826           return this.renderer.listitem(body);
17827         }
17828         case 'html': {
17829           var html = !this.token.pre && !this.options.pedantic
17830             ? this.inline.output(this.token.text)
17831             : this.token.text;
17832           return this.renderer.html(html);
17833         }
17834         case 'paragraph': {
17835           return this.renderer.paragraph(this.inline.output(this.token.text));
17836         }
17837         case 'text': {
17838           return this.renderer.paragraph(this.parseText());
17839         }
17840       }
17841     };
17842     
17843     /**
17844      * Helpers
17845      */
17846     
17847     function escape(html, encode) {
17848       return html
17849         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17850         .replace(/</g, '&lt;')
17851         .replace(/>/g, '&gt;')
17852         .replace(/"/g, '&quot;')
17853         .replace(/'/g, '&#39;');
17854     }
17855     
17856     function unescape(html) {
17857         // explicitly match decimal, hex, and named HTML entities 
17858       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17859         n = n.toLowerCase();
17860         if (n === 'colon') { return ':'; }
17861         if (n.charAt(0) === '#') {
17862           return n.charAt(1) === 'x'
17863             ? String.fromCharCode(parseInt(n.substring(2), 16))
17864             : String.fromCharCode(+n.substring(1));
17865         }
17866         return '';
17867       });
17868     }
17869     
17870     function replace(regex, opt) {
17871       regex = regex.source;
17872       opt = opt || '';
17873       return function self(name, val) {
17874         if (!name) { return new RegExp(regex, opt); }
17875         val = val.source || val;
17876         val = val.replace(/(^|[^\[])\^/g, '$1');
17877         regex = regex.replace(name, val);
17878         return self;
17879       };
17880     }
17881     
17882     function noop() {}
17883     noop.exec = noop;
17884     
17885     function merge(obj) {
17886       var i = 1
17887         , target
17888         , key;
17889     
17890       for (; i < arguments.length; i++) {
17891         target = arguments[i];
17892         for (key in target) {
17893           if (Object.prototype.hasOwnProperty.call(target, key)) {
17894             obj[key] = target[key];
17895           }
17896         }
17897       }
17898     
17899       return obj;
17900     }
17901     
17902     
17903     /**
17904      * Marked
17905      */
17906     
17907     function marked(src, opt, callback) {
17908       if (callback || typeof opt === 'function') {
17909         if (!callback) {
17910           callback = opt;
17911           opt = null;
17912         }
17913     
17914         opt = merge({}, marked.defaults, opt || {});
17915     
17916         var highlight = opt.highlight
17917           , tokens
17918           , pending
17919           , i = 0;
17920     
17921         try {
17922           tokens = Lexer.lex(src, opt)
17923         } catch (e) {
17924           return callback(e);
17925         }
17926     
17927         pending = tokens.length;
17928     
17929         var done = function(err) {
17930           if (err) {
17931             opt.highlight = highlight;
17932             return callback(err);
17933           }
17934     
17935           var out;
17936     
17937           try {
17938             out = Parser.parse(tokens, opt);
17939           } catch (e) {
17940             err = e;
17941           }
17942     
17943           opt.highlight = highlight;
17944     
17945           return err
17946             ? callback(err)
17947             : callback(null, out);
17948         };
17949     
17950         if (!highlight || highlight.length < 3) {
17951           return done();
17952         }
17953     
17954         delete opt.highlight;
17955     
17956         if (!pending) { return done(); }
17957     
17958         for (; i < tokens.length; i++) {
17959           (function(token) {
17960             if (token.type !== 'code') {
17961               return --pending || done();
17962             }
17963             return highlight(token.text, token.lang, function(err, code) {
17964               if (err) { return done(err); }
17965               if (code == null || code === token.text) {
17966                 return --pending || done();
17967               }
17968               token.text = code;
17969               token.escaped = true;
17970               --pending || done();
17971             });
17972           })(tokens[i]);
17973         }
17974     
17975         return;
17976       }
17977       try {
17978         if (opt) { opt = merge({}, marked.defaults, opt); }
17979         return Parser.parse(Lexer.lex(src, opt), opt);
17980       } catch (e) {
17981         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17982         if ((opt || marked.defaults).silent) {
17983           return '<p>An error occured:</p><pre>'
17984             + escape(e.message + '', true)
17985             + '</pre>';
17986         }
17987         throw e;
17988       }
17989     }
17990     
17991     /**
17992      * Options
17993      */
17994     
17995     marked.options =
17996     marked.setOptions = function(opt) {
17997       merge(marked.defaults, opt);
17998       return marked;
17999     };
18000     
18001     marked.defaults = {
18002       gfm: true,
18003       tables: true,
18004       breaks: false,
18005       pedantic: false,
18006       sanitize: false,
18007       sanitizer: null,
18008       mangle: true,
18009       smartLists: false,
18010       silent: false,
18011       highlight: null,
18012       langPrefix: 'lang-',
18013       smartypants: false,
18014       headerPrefix: '',
18015       renderer: new Renderer,
18016       xhtml: false
18017     };
18018     
18019     /**
18020      * Expose
18021      */
18022     
18023     marked.Parser = Parser;
18024     marked.parser = Parser.parse;
18025     
18026     marked.Renderer = Renderer;
18027     
18028     marked.Lexer = Lexer;
18029     marked.lexer = Lexer.lex;
18030     
18031     marked.InlineLexer = InlineLexer;
18032     marked.inlineLexer = InlineLexer.output;
18033     
18034     marked.parse = marked;
18035     
18036     Roo.Markdown.marked = marked;
18037
18038 })();/*
18039  * Based on:
18040  * Ext JS Library 1.1.1
18041  * Copyright(c) 2006-2007, Ext JS, LLC.
18042  *
18043  * Originally Released Under LGPL - original licence link has changed is not relivant.
18044  *
18045  * Fork - LGPL
18046  * <script type="text/javascript">
18047  */
18048
18049
18050
18051 /*
18052  * These classes are derivatives of the similarly named classes in the YUI Library.
18053  * The original license:
18054  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18055  * Code licensed under the BSD License:
18056  * http://developer.yahoo.net/yui/license.txt
18057  */
18058
18059 (function() {
18060
18061 var Event=Roo.EventManager;
18062 var Dom=Roo.lib.Dom;
18063
18064 /**
18065  * @class Roo.dd.DragDrop
18066  * @extends Roo.util.Observable
18067  * Defines the interface and base operation of items that that can be
18068  * dragged or can be drop targets.  It was designed to be extended, overriding
18069  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18070  * Up to three html elements can be associated with a DragDrop instance:
18071  * <ul>
18072  * <li>linked element: the element that is passed into the constructor.
18073  * This is the element which defines the boundaries for interaction with
18074  * other DragDrop objects.</li>
18075  * <li>handle element(s): The drag operation only occurs if the element that
18076  * was clicked matches a handle element.  By default this is the linked
18077  * element, but there are times that you will want only a portion of the
18078  * linked element to initiate the drag operation, and the setHandleElId()
18079  * method provides a way to define this.</li>
18080  * <li>drag element: this represents the element that would be moved along
18081  * with the cursor during a drag operation.  By default, this is the linked
18082  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18083  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18084  * </li>
18085  * </ul>
18086  * This class should not be instantiated until the onload event to ensure that
18087  * the associated elements are available.
18088  * The following would define a DragDrop obj that would interact with any
18089  * other DragDrop obj in the "group1" group:
18090  * <pre>
18091  *  dd = new Roo.dd.DragDrop("div1", "group1");
18092  * </pre>
18093  * Since none of the event handlers have been implemented, nothing would
18094  * actually happen if you were to run the code above.  Normally you would
18095  * override this class or one of the default implementations, but you can
18096  * also override the methods you want on an instance of the class...
18097  * <pre>
18098  *  dd.onDragDrop = function(e, id) {
18099  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18100  *  }
18101  * </pre>
18102  * @constructor
18103  * @param {String} id of the element that is linked to this instance
18104  * @param {String} sGroup the group of related DragDrop objects
18105  * @param {object} config an object containing configurable attributes
18106  *                Valid properties for DragDrop:
18107  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18108  */
18109 Roo.dd.DragDrop = function(id, sGroup, config) {
18110     if (id) {
18111         this.init(id, sGroup, config);
18112     }
18113     
18114 };
18115
18116 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18117
18118     /**
18119      * The id of the element associated with this object.  This is what we
18120      * refer to as the "linked element" because the size and position of
18121      * this element is used to determine when the drag and drop objects have
18122      * interacted.
18123      * @property id
18124      * @type String
18125      */
18126     id: null,
18127
18128     /**
18129      * Configuration attributes passed into the constructor
18130      * @property config
18131      * @type object
18132      */
18133     config: null,
18134
18135     /**
18136      * The id of the element that will be dragged.  By default this is same
18137      * as the linked element , but could be changed to another element. Ex:
18138      * Roo.dd.DDProxy
18139      * @property dragElId
18140      * @type String
18141      * @private
18142      */
18143     dragElId: null,
18144
18145     /**
18146      * the id of the element that initiates the drag operation.  By default
18147      * this is the linked element, but could be changed to be a child of this
18148      * element.  This lets us do things like only starting the drag when the
18149      * header element within the linked html element is clicked.
18150      * @property handleElId
18151      * @type String
18152      * @private
18153      */
18154     handleElId: null,
18155
18156     /**
18157      * An associative array of HTML tags that will be ignored if clicked.
18158      * @property invalidHandleTypes
18159      * @type {string: string}
18160      */
18161     invalidHandleTypes: null,
18162
18163     /**
18164      * An associative array of ids for elements that will be ignored if clicked
18165      * @property invalidHandleIds
18166      * @type {string: string}
18167      */
18168     invalidHandleIds: null,
18169
18170     /**
18171      * An indexted array of css class names for elements that will be ignored
18172      * if clicked.
18173      * @property invalidHandleClasses
18174      * @type string[]
18175      */
18176     invalidHandleClasses: null,
18177
18178     /**
18179      * The linked element's absolute X position at the time the drag was
18180      * started
18181      * @property startPageX
18182      * @type int
18183      * @private
18184      */
18185     startPageX: 0,
18186
18187     /**
18188      * The linked element's absolute X position at the time the drag was
18189      * started
18190      * @property startPageY
18191      * @type int
18192      * @private
18193      */
18194     startPageY: 0,
18195
18196     /**
18197      * The group defines a logical collection of DragDrop objects that are
18198      * related.  Instances only get events when interacting with other
18199      * DragDrop object in the same group.  This lets us define multiple
18200      * groups using a single DragDrop subclass if we want.
18201      * @property groups
18202      * @type {string: string}
18203      */
18204     groups: null,
18205
18206     /**
18207      * Individual drag/drop instances can be locked.  This will prevent
18208      * onmousedown start drag.
18209      * @property locked
18210      * @type boolean
18211      * @private
18212      */
18213     locked: false,
18214
18215     /**
18216      * Lock this instance
18217      * @method lock
18218      */
18219     lock: function() { this.locked = true; },
18220
18221     /**
18222      * Unlock this instace
18223      * @method unlock
18224      */
18225     unlock: function() { this.locked = false; },
18226
18227     /**
18228      * By default, all insances can be a drop target.  This can be disabled by
18229      * setting isTarget to false.
18230      * @method isTarget
18231      * @type boolean
18232      */
18233     isTarget: true,
18234
18235     /**
18236      * The padding configured for this drag and drop object for calculating
18237      * the drop zone intersection with this object.
18238      * @method padding
18239      * @type int[]
18240      */
18241     padding: null,
18242
18243     /**
18244      * Cached reference to the linked element
18245      * @property _domRef
18246      * @private
18247      */
18248     _domRef: null,
18249
18250     /**
18251      * Internal typeof flag
18252      * @property __ygDragDrop
18253      * @private
18254      */
18255     __ygDragDrop: true,
18256
18257     /**
18258      * Set to true when horizontal contraints are applied
18259      * @property constrainX
18260      * @type boolean
18261      * @private
18262      */
18263     constrainX: false,
18264
18265     /**
18266      * Set to true when vertical contraints are applied
18267      * @property constrainY
18268      * @type boolean
18269      * @private
18270      */
18271     constrainY: false,
18272
18273     /**
18274      * The left constraint
18275      * @property minX
18276      * @type int
18277      * @private
18278      */
18279     minX: 0,
18280
18281     /**
18282      * The right constraint
18283      * @property maxX
18284      * @type int
18285      * @private
18286      */
18287     maxX: 0,
18288
18289     /**
18290      * The up constraint
18291      * @property minY
18292      * @type int
18293      * @type int
18294      * @private
18295      */
18296     minY: 0,
18297
18298     /**
18299      * The down constraint
18300      * @property maxY
18301      * @type int
18302      * @private
18303      */
18304     maxY: 0,
18305
18306     /**
18307      * Maintain offsets when we resetconstraints.  Set to true when you want
18308      * the position of the element relative to its parent to stay the same
18309      * when the page changes
18310      *
18311      * @property maintainOffset
18312      * @type boolean
18313      */
18314     maintainOffset: false,
18315
18316     /**
18317      * Array of pixel locations the element will snap to if we specified a
18318      * horizontal graduation/interval.  This array is generated automatically
18319      * when you define a tick interval.
18320      * @property xTicks
18321      * @type int[]
18322      */
18323     xTicks: null,
18324
18325     /**
18326      * Array of pixel locations the element will snap to if we specified a
18327      * vertical graduation/interval.  This array is generated automatically
18328      * when you define a tick interval.
18329      * @property yTicks
18330      * @type int[]
18331      */
18332     yTicks: null,
18333
18334     /**
18335      * By default the drag and drop instance will only respond to the primary
18336      * button click (left button for a right-handed mouse).  Set to true to
18337      * allow drag and drop to start with any mouse click that is propogated
18338      * by the browser
18339      * @property primaryButtonOnly
18340      * @type boolean
18341      */
18342     primaryButtonOnly: true,
18343
18344     /**
18345      * The availabe property is false until the linked dom element is accessible.
18346      * @property available
18347      * @type boolean
18348      */
18349     available: false,
18350
18351     /**
18352      * By default, drags can only be initiated if the mousedown occurs in the
18353      * region the linked element is.  This is done in part to work around a
18354      * bug in some browsers that mis-report the mousedown if the previous
18355      * mouseup happened outside of the window.  This property is set to true
18356      * if outer handles are defined.
18357      *
18358      * @property hasOuterHandles
18359      * @type boolean
18360      * @default false
18361      */
18362     hasOuterHandles: false,
18363
18364     /**
18365      * Code that executes immediately before the startDrag event
18366      * @method b4StartDrag
18367      * @private
18368      */
18369     b4StartDrag: function(x, y) { },
18370
18371     /**
18372      * Abstract method called after a drag/drop object is clicked
18373      * and the drag or mousedown time thresholds have beeen met.
18374      * @method startDrag
18375      * @param {int} X click location
18376      * @param {int} Y click location
18377      */
18378     startDrag: function(x, y) { /* override this */ },
18379
18380     /**
18381      * Code that executes immediately before the onDrag event
18382      * @method b4Drag
18383      * @private
18384      */
18385     b4Drag: function(e) { },
18386
18387     /**
18388      * Abstract method called during the onMouseMove event while dragging an
18389      * object.
18390      * @method onDrag
18391      * @param {Event} e the mousemove event
18392      */
18393     onDrag: function(e) { /* override this */ },
18394
18395     /**
18396      * Abstract method called when this element fist begins hovering over
18397      * another DragDrop obj
18398      * @method onDragEnter
18399      * @param {Event} e the mousemove event
18400      * @param {String|DragDrop[]} id In POINT mode, the element
18401      * id this is hovering over.  In INTERSECT mode, an array of one or more
18402      * dragdrop items being hovered over.
18403      */
18404     onDragEnter: function(e, id) { /* override this */ },
18405
18406     /**
18407      * Code that executes immediately before the onDragOver event
18408      * @method b4DragOver
18409      * @private
18410      */
18411     b4DragOver: function(e) { },
18412
18413     /**
18414      * Abstract method called when this element is hovering over another
18415      * DragDrop obj
18416      * @method onDragOver
18417      * @param {Event} e the mousemove event
18418      * @param {String|DragDrop[]} id In POINT mode, the element
18419      * id this is hovering over.  In INTERSECT mode, an array of dd items
18420      * being hovered over.
18421      */
18422     onDragOver: function(e, id) { /* override this */ },
18423
18424     /**
18425      * Code that executes immediately before the onDragOut event
18426      * @method b4DragOut
18427      * @private
18428      */
18429     b4DragOut: function(e) { },
18430
18431     /**
18432      * Abstract method called when we are no longer hovering over an element
18433      * @method onDragOut
18434      * @param {Event} e the mousemove event
18435      * @param {String|DragDrop[]} id In POINT mode, the element
18436      * id this was hovering over.  In INTERSECT mode, an array of dd items
18437      * that the mouse is no longer over.
18438      */
18439     onDragOut: function(e, id) { /* override this */ },
18440
18441     /**
18442      * Code that executes immediately before the onDragDrop event
18443      * @method b4DragDrop
18444      * @private
18445      */
18446     b4DragDrop: function(e) { },
18447
18448     /**
18449      * Abstract method called when this item is dropped on another DragDrop
18450      * obj
18451      * @method onDragDrop
18452      * @param {Event} e the mouseup event
18453      * @param {String|DragDrop[]} id In POINT mode, the element
18454      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18455      * was dropped on.
18456      */
18457     onDragDrop: function(e, id) { /* override this */ },
18458
18459     /**
18460      * Abstract method called when this item is dropped on an area with no
18461      * drop target
18462      * @method onInvalidDrop
18463      * @param {Event} e the mouseup event
18464      */
18465     onInvalidDrop: function(e) { /* override this */ },
18466
18467     /**
18468      * Code that executes immediately before the endDrag event
18469      * @method b4EndDrag
18470      * @private
18471      */
18472     b4EndDrag: function(e) { },
18473
18474     /**
18475      * Fired when we are done dragging the object
18476      * @method endDrag
18477      * @param {Event} e the mouseup event
18478      */
18479     endDrag: function(e) { /* override this */ },
18480
18481     /**
18482      * Code executed immediately before the onMouseDown event
18483      * @method b4MouseDown
18484      * @param {Event} e the mousedown event
18485      * @private
18486      */
18487     b4MouseDown: function(e) {  },
18488
18489     /**
18490      * Event handler that fires when a drag/drop obj gets a mousedown
18491      * @method onMouseDown
18492      * @param {Event} e the mousedown event
18493      */
18494     onMouseDown: function(e) { /* override this */ },
18495
18496     /**
18497      * Event handler that fires when a drag/drop obj gets a mouseup
18498      * @method onMouseUp
18499      * @param {Event} e the mouseup event
18500      */
18501     onMouseUp: function(e) { /* override this */ },
18502
18503     /**
18504      * Override the onAvailable method to do what is needed after the initial
18505      * position was determined.
18506      * @method onAvailable
18507      */
18508     onAvailable: function () {
18509     },
18510
18511     /*
18512      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18513      * @type Object
18514      */
18515     defaultPadding : {left:0, right:0, top:0, bottom:0},
18516
18517     /*
18518      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18519  *
18520  * Usage:
18521  <pre><code>
18522  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18523                 { dragElId: "existingProxyDiv" });
18524  dd.startDrag = function(){
18525      this.constrainTo("parent-id");
18526  };
18527  </code></pre>
18528  * Or you can initalize it using the {@link Roo.Element} object:
18529  <pre><code>
18530  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18531      startDrag : function(){
18532          this.constrainTo("parent-id");
18533      }
18534  });
18535  </code></pre>
18536      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18537      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18538      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18539      * an object containing the sides to pad. For example: {right:10, bottom:10}
18540      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18541      */
18542     constrainTo : function(constrainTo, pad, inContent){
18543         if(typeof pad == "number"){
18544             pad = {left: pad, right:pad, top:pad, bottom:pad};
18545         }
18546         pad = pad || this.defaultPadding;
18547         var b = Roo.get(this.getEl()).getBox();
18548         var ce = Roo.get(constrainTo);
18549         var s = ce.getScroll();
18550         var c, cd = ce.dom;
18551         if(cd == document.body){
18552             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18553         }else{
18554             xy = ce.getXY();
18555             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18556         }
18557
18558
18559         var topSpace = b.y - c.y;
18560         var leftSpace = b.x - c.x;
18561
18562         this.resetConstraints();
18563         this.setXConstraint(leftSpace - (pad.left||0), // left
18564                 c.width - leftSpace - b.width - (pad.right||0) //right
18565         );
18566         this.setYConstraint(topSpace - (pad.top||0), //top
18567                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18568         );
18569     },
18570
18571     /**
18572      * Returns a reference to the linked element
18573      * @method getEl
18574      * @return {HTMLElement} the html element
18575      */
18576     getEl: function() {
18577         if (!this._domRef) {
18578             this._domRef = Roo.getDom(this.id);
18579         }
18580
18581         return this._domRef;
18582     },
18583
18584     /**
18585      * Returns a reference to the actual element to drag.  By default this is
18586      * the same as the html element, but it can be assigned to another
18587      * element. An example of this can be found in Roo.dd.DDProxy
18588      * @method getDragEl
18589      * @return {HTMLElement} the html element
18590      */
18591     getDragEl: function() {
18592         return Roo.getDom(this.dragElId);
18593     },
18594
18595     /**
18596      * Sets up the DragDrop object.  Must be called in the constructor of any
18597      * Roo.dd.DragDrop subclass
18598      * @method init
18599      * @param id the id of the linked element
18600      * @param {String} sGroup the group of related items
18601      * @param {object} config configuration attributes
18602      */
18603     init: function(id, sGroup, config) {
18604         this.initTarget(id, sGroup, config);
18605         if (!Roo.isTouch) {
18606             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18607         }
18608         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18609         // Event.on(this.id, "selectstart", Event.preventDefault);
18610     },
18611
18612     /**
18613      * Initializes Targeting functionality only... the object does not
18614      * get a mousedown handler.
18615      * @method initTarget
18616      * @param id the id of the linked element
18617      * @param {String} sGroup the group of related items
18618      * @param {object} config configuration attributes
18619      */
18620     initTarget: function(id, sGroup, config) {
18621
18622         // configuration attributes
18623         this.config = config || {};
18624
18625         // create a local reference to the drag and drop manager
18626         this.DDM = Roo.dd.DDM;
18627         // initialize the groups array
18628         this.groups = {};
18629
18630         // assume that we have an element reference instead of an id if the
18631         // parameter is not a string
18632         if (typeof id !== "string") {
18633             id = Roo.id(id);
18634         }
18635
18636         // set the id
18637         this.id = id;
18638
18639         // add to an interaction group
18640         this.addToGroup((sGroup) ? sGroup : "default");
18641
18642         // We don't want to register this as the handle with the manager
18643         // so we just set the id rather than calling the setter.
18644         this.handleElId = id;
18645
18646         // the linked element is the element that gets dragged by default
18647         this.setDragElId(id);
18648
18649         // by default, clicked anchors will not start drag operations.
18650         this.invalidHandleTypes = { A: "A" };
18651         this.invalidHandleIds = {};
18652         this.invalidHandleClasses = [];
18653
18654         this.applyConfig();
18655
18656         this.handleOnAvailable();
18657     },
18658
18659     /**
18660      * Applies the configuration parameters that were passed into the constructor.
18661      * This is supposed to happen at each level through the inheritance chain.  So
18662      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18663      * DragDrop in order to get all of the parameters that are available in
18664      * each object.
18665      * @method applyConfig
18666      */
18667     applyConfig: function() {
18668
18669         // configurable properties:
18670         //    padding, isTarget, maintainOffset, primaryButtonOnly
18671         this.padding           = this.config.padding || [0, 0, 0, 0];
18672         this.isTarget          = (this.config.isTarget !== false);
18673         this.maintainOffset    = (this.config.maintainOffset);
18674         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18675
18676     },
18677
18678     /**
18679      * Executed when the linked element is available
18680      * @method handleOnAvailable
18681      * @private
18682      */
18683     handleOnAvailable: function() {
18684         this.available = true;
18685         this.resetConstraints();
18686         this.onAvailable();
18687     },
18688
18689      /**
18690      * Configures the padding for the target zone in px.  Effectively expands
18691      * (or reduces) the virtual object size for targeting calculations.
18692      * Supports css-style shorthand; if only one parameter is passed, all sides
18693      * will have that padding, and if only two are passed, the top and bottom
18694      * will have the first param, the left and right the second.
18695      * @method setPadding
18696      * @param {int} iTop    Top pad
18697      * @param {int} iRight  Right pad
18698      * @param {int} iBot    Bot pad
18699      * @param {int} iLeft   Left pad
18700      */
18701     setPadding: function(iTop, iRight, iBot, iLeft) {
18702         // this.padding = [iLeft, iRight, iTop, iBot];
18703         if (!iRight && 0 !== iRight) {
18704             this.padding = [iTop, iTop, iTop, iTop];
18705         } else if (!iBot && 0 !== iBot) {
18706             this.padding = [iTop, iRight, iTop, iRight];
18707         } else {
18708             this.padding = [iTop, iRight, iBot, iLeft];
18709         }
18710     },
18711
18712     /**
18713      * Stores the initial placement of the linked element.
18714      * @method setInitialPosition
18715      * @param {int} diffX   the X offset, default 0
18716      * @param {int} diffY   the Y offset, default 0
18717      */
18718     setInitPosition: function(diffX, diffY) {
18719         var el = this.getEl();
18720
18721         if (!this.DDM.verifyEl(el)) {
18722             return;
18723         }
18724
18725         var dx = diffX || 0;
18726         var dy = diffY || 0;
18727
18728         var p = Dom.getXY( el );
18729
18730         this.initPageX = p[0] - dx;
18731         this.initPageY = p[1] - dy;
18732
18733         this.lastPageX = p[0];
18734         this.lastPageY = p[1];
18735
18736
18737         this.setStartPosition(p);
18738     },
18739
18740     /**
18741      * Sets the start position of the element.  This is set when the obj
18742      * is initialized, the reset when a drag is started.
18743      * @method setStartPosition
18744      * @param pos current position (from previous lookup)
18745      * @private
18746      */
18747     setStartPosition: function(pos) {
18748         var p = pos || Dom.getXY( this.getEl() );
18749         this.deltaSetXY = null;
18750
18751         this.startPageX = p[0];
18752         this.startPageY = p[1];
18753     },
18754
18755     /**
18756      * Add this instance to a group of related drag/drop objects.  All
18757      * instances belong to at least one group, and can belong to as many
18758      * groups as needed.
18759      * @method addToGroup
18760      * @param sGroup {string} the name of the group
18761      */
18762     addToGroup: function(sGroup) {
18763         this.groups[sGroup] = true;
18764         this.DDM.regDragDrop(this, sGroup);
18765     },
18766
18767     /**
18768      * Remove's this instance from the supplied interaction group
18769      * @method removeFromGroup
18770      * @param {string}  sGroup  The group to drop
18771      */
18772     removeFromGroup: function(sGroup) {
18773         if (this.groups[sGroup]) {
18774             delete this.groups[sGroup];
18775         }
18776
18777         this.DDM.removeDDFromGroup(this, sGroup);
18778     },
18779
18780     /**
18781      * Allows you to specify that an element other than the linked element
18782      * will be moved with the cursor during a drag
18783      * @method setDragElId
18784      * @param id {string} the id of the element that will be used to initiate the drag
18785      */
18786     setDragElId: function(id) {
18787         this.dragElId = id;
18788     },
18789
18790     /**
18791      * Allows you to specify a child of the linked element that should be
18792      * used to initiate the drag operation.  An example of this would be if
18793      * you have a content div with text and links.  Clicking anywhere in the
18794      * content area would normally start the drag operation.  Use this method
18795      * to specify that an element inside of the content div is the element
18796      * that starts the drag operation.
18797      * @method setHandleElId
18798      * @param id {string} the id of the element that will be used to
18799      * initiate the drag.
18800      */
18801     setHandleElId: function(id) {
18802         if (typeof id !== "string") {
18803             id = Roo.id(id);
18804         }
18805         this.handleElId = id;
18806         this.DDM.regHandle(this.id, id);
18807     },
18808
18809     /**
18810      * Allows you to set an element outside of the linked element as a drag
18811      * handle
18812      * @method setOuterHandleElId
18813      * @param id the id of the element that will be used to initiate the drag
18814      */
18815     setOuterHandleElId: function(id) {
18816         if (typeof id !== "string") {
18817             id = Roo.id(id);
18818         }
18819         Event.on(id, "mousedown",
18820                 this.handleMouseDown, this);
18821         this.setHandleElId(id);
18822
18823         this.hasOuterHandles = true;
18824     },
18825
18826     /**
18827      * Remove all drag and drop hooks for this element
18828      * @method unreg
18829      */
18830     unreg: function() {
18831         Event.un(this.id, "mousedown",
18832                 this.handleMouseDown);
18833         Event.un(this.id, "touchstart",
18834                 this.handleMouseDown);
18835         this._domRef = null;
18836         this.DDM._remove(this);
18837     },
18838
18839     destroy : function(){
18840         this.unreg();
18841     },
18842
18843     /**
18844      * Returns true if this instance is locked, or the drag drop mgr is locked
18845      * (meaning that all drag/drop is disabled on the page.)
18846      * @method isLocked
18847      * @return {boolean} true if this obj or all drag/drop is locked, else
18848      * false
18849      */
18850     isLocked: function() {
18851         return (this.DDM.isLocked() || this.locked);
18852     },
18853
18854     /**
18855      * Fired when this object is clicked
18856      * @method handleMouseDown
18857      * @param {Event} e
18858      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18859      * @private
18860      */
18861     handleMouseDown: function(e, oDD){
18862      
18863         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18864             //Roo.log('not touch/ button !=0');
18865             return;
18866         }
18867         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18868             return; // double touch..
18869         }
18870         
18871
18872         if (this.isLocked()) {
18873             //Roo.log('locked');
18874             return;
18875         }
18876
18877         this.DDM.refreshCache(this.groups);
18878 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18879         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18880         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18881             //Roo.log('no outer handes or not over target');
18882                 // do nothing.
18883         } else {
18884 //            Roo.log('check validator');
18885             if (this.clickValidator(e)) {
18886 //                Roo.log('validate success');
18887                 // set the initial element position
18888                 this.setStartPosition();
18889
18890
18891                 this.b4MouseDown(e);
18892                 this.onMouseDown(e);
18893
18894                 this.DDM.handleMouseDown(e, this);
18895
18896                 this.DDM.stopEvent(e);
18897             } else {
18898
18899
18900             }
18901         }
18902     },
18903
18904     clickValidator: function(e) {
18905         var target = e.getTarget();
18906         return ( this.isValidHandleChild(target) &&
18907                     (this.id == this.handleElId ||
18908                         this.DDM.handleWasClicked(target, this.id)) );
18909     },
18910
18911     /**
18912      * Allows you to specify a tag name that should not start a drag operation
18913      * when clicked.  This is designed to facilitate embedding links within a
18914      * drag handle that do something other than start the drag.
18915      * @method addInvalidHandleType
18916      * @param {string} tagName the type of element to exclude
18917      */
18918     addInvalidHandleType: function(tagName) {
18919         var type = tagName.toUpperCase();
18920         this.invalidHandleTypes[type] = type;
18921     },
18922
18923     /**
18924      * Lets you to specify an element id for a child of a drag handle
18925      * that should not initiate a drag
18926      * @method addInvalidHandleId
18927      * @param {string} id the element id of the element you wish to ignore
18928      */
18929     addInvalidHandleId: function(id) {
18930         if (typeof id !== "string") {
18931             id = Roo.id(id);
18932         }
18933         this.invalidHandleIds[id] = id;
18934     },
18935
18936     /**
18937      * Lets you specify a css class of elements that will not initiate a drag
18938      * @method addInvalidHandleClass
18939      * @param {string} cssClass the class of the elements you wish to ignore
18940      */
18941     addInvalidHandleClass: function(cssClass) {
18942         this.invalidHandleClasses.push(cssClass);
18943     },
18944
18945     /**
18946      * Unsets an excluded tag name set by addInvalidHandleType
18947      * @method removeInvalidHandleType
18948      * @param {string} tagName the type of element to unexclude
18949      */
18950     removeInvalidHandleType: function(tagName) {
18951         var type = tagName.toUpperCase();
18952         // this.invalidHandleTypes[type] = null;
18953         delete this.invalidHandleTypes[type];
18954     },
18955
18956     /**
18957      * Unsets an invalid handle id
18958      * @method removeInvalidHandleId
18959      * @param {string} id the id of the element to re-enable
18960      */
18961     removeInvalidHandleId: function(id) {
18962         if (typeof id !== "string") {
18963             id = Roo.id(id);
18964         }
18965         delete this.invalidHandleIds[id];
18966     },
18967
18968     /**
18969      * Unsets an invalid css class
18970      * @method removeInvalidHandleClass
18971      * @param {string} cssClass the class of the element(s) you wish to
18972      * re-enable
18973      */
18974     removeInvalidHandleClass: function(cssClass) {
18975         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18976             if (this.invalidHandleClasses[i] == cssClass) {
18977                 delete this.invalidHandleClasses[i];
18978             }
18979         }
18980     },
18981
18982     /**
18983      * Checks the tag exclusion list to see if this click should be ignored
18984      * @method isValidHandleChild
18985      * @param {HTMLElement} node the HTMLElement to evaluate
18986      * @return {boolean} true if this is a valid tag type, false if not
18987      */
18988     isValidHandleChild: function(node) {
18989
18990         var valid = true;
18991         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18992         var nodeName;
18993         try {
18994             nodeName = node.nodeName.toUpperCase();
18995         } catch(e) {
18996             nodeName = node.nodeName;
18997         }
18998         valid = valid && !this.invalidHandleTypes[nodeName];
18999         valid = valid && !this.invalidHandleIds[node.id];
19000
19001         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19002             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19003         }
19004
19005
19006         return valid;
19007
19008     },
19009
19010     /**
19011      * Create the array of horizontal tick marks if an interval was specified
19012      * in setXConstraint().
19013      * @method setXTicks
19014      * @private
19015      */
19016     setXTicks: function(iStartX, iTickSize) {
19017         this.xTicks = [];
19018         this.xTickSize = iTickSize;
19019
19020         var tickMap = {};
19021
19022         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19023             if (!tickMap[i]) {
19024                 this.xTicks[this.xTicks.length] = i;
19025                 tickMap[i] = true;
19026             }
19027         }
19028
19029         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19030             if (!tickMap[i]) {
19031                 this.xTicks[this.xTicks.length] = i;
19032                 tickMap[i] = true;
19033             }
19034         }
19035
19036         this.xTicks.sort(this.DDM.numericSort) ;
19037     },
19038
19039     /**
19040      * Create the array of vertical tick marks if an interval was specified in
19041      * setYConstraint().
19042      * @method setYTicks
19043      * @private
19044      */
19045     setYTicks: function(iStartY, iTickSize) {
19046         this.yTicks = [];
19047         this.yTickSize = iTickSize;
19048
19049         var tickMap = {};
19050
19051         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19052             if (!tickMap[i]) {
19053                 this.yTicks[this.yTicks.length] = i;
19054                 tickMap[i] = true;
19055             }
19056         }
19057
19058         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19059             if (!tickMap[i]) {
19060                 this.yTicks[this.yTicks.length] = i;
19061                 tickMap[i] = true;
19062             }
19063         }
19064
19065         this.yTicks.sort(this.DDM.numericSort) ;
19066     },
19067
19068     /**
19069      * By default, the element can be dragged any place on the screen.  Use
19070      * this method to limit the horizontal travel of the element.  Pass in
19071      * 0,0 for the parameters if you want to lock the drag to the y axis.
19072      * @method setXConstraint
19073      * @param {int} iLeft the number of pixels the element can move to the left
19074      * @param {int} iRight the number of pixels the element can move to the
19075      * right
19076      * @param {int} iTickSize optional parameter for specifying that the
19077      * element
19078      * should move iTickSize pixels at a time.
19079      */
19080     setXConstraint: function(iLeft, iRight, iTickSize) {
19081         this.leftConstraint = iLeft;
19082         this.rightConstraint = iRight;
19083
19084         this.minX = this.initPageX - iLeft;
19085         this.maxX = this.initPageX + iRight;
19086         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19087
19088         this.constrainX = true;
19089     },
19090
19091     /**
19092      * Clears any constraints applied to this instance.  Also clears ticks
19093      * since they can't exist independent of a constraint at this time.
19094      * @method clearConstraints
19095      */
19096     clearConstraints: function() {
19097         this.constrainX = false;
19098         this.constrainY = false;
19099         this.clearTicks();
19100     },
19101
19102     /**
19103      * Clears any tick interval defined for this instance
19104      * @method clearTicks
19105      */
19106     clearTicks: function() {
19107         this.xTicks = null;
19108         this.yTicks = null;
19109         this.xTickSize = 0;
19110         this.yTickSize = 0;
19111     },
19112
19113     /**
19114      * By default, the element can be dragged any place on the screen.  Set
19115      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19116      * parameters if you want to lock the drag to the x axis.
19117      * @method setYConstraint
19118      * @param {int} iUp the number of pixels the element can move up
19119      * @param {int} iDown the number of pixels the element can move down
19120      * @param {int} iTickSize optional parameter for specifying that the
19121      * element should move iTickSize pixels at a time.
19122      */
19123     setYConstraint: function(iUp, iDown, iTickSize) {
19124         this.topConstraint = iUp;
19125         this.bottomConstraint = iDown;
19126
19127         this.minY = this.initPageY - iUp;
19128         this.maxY = this.initPageY + iDown;
19129         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19130
19131         this.constrainY = true;
19132
19133     },
19134
19135     /**
19136      * resetConstraints must be called if you manually reposition a dd element.
19137      * @method resetConstraints
19138      * @param {boolean} maintainOffset
19139      */
19140     resetConstraints: function() {
19141
19142
19143         // Maintain offsets if necessary
19144         if (this.initPageX || this.initPageX === 0) {
19145             // figure out how much this thing has moved
19146             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19147             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19148
19149             this.setInitPosition(dx, dy);
19150
19151         // This is the first time we have detected the element's position
19152         } else {
19153             this.setInitPosition();
19154         }
19155
19156         if (this.constrainX) {
19157             this.setXConstraint( this.leftConstraint,
19158                                  this.rightConstraint,
19159                                  this.xTickSize        );
19160         }
19161
19162         if (this.constrainY) {
19163             this.setYConstraint( this.topConstraint,
19164                                  this.bottomConstraint,
19165                                  this.yTickSize         );
19166         }
19167     },
19168
19169     /**
19170      * Normally the drag element is moved pixel by pixel, but we can specify
19171      * that it move a number of pixels at a time.  This method resolves the
19172      * location when we have it set up like this.
19173      * @method getTick
19174      * @param {int} val where we want to place the object
19175      * @param {int[]} tickArray sorted array of valid points
19176      * @return {int} the closest tick
19177      * @private
19178      */
19179     getTick: function(val, tickArray) {
19180
19181         if (!tickArray) {
19182             // If tick interval is not defined, it is effectively 1 pixel,
19183             // so we return the value passed to us.
19184             return val;
19185         } else if (tickArray[0] >= val) {
19186             // The value is lower than the first tick, so we return the first
19187             // tick.
19188             return tickArray[0];
19189         } else {
19190             for (var i=0, len=tickArray.length; i<len; ++i) {
19191                 var next = i + 1;
19192                 if (tickArray[next] && tickArray[next] >= val) {
19193                     var diff1 = val - tickArray[i];
19194                     var diff2 = tickArray[next] - val;
19195                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19196                 }
19197             }
19198
19199             // The value is larger than the last tick, so we return the last
19200             // tick.
19201             return tickArray[tickArray.length - 1];
19202         }
19203     },
19204
19205     /**
19206      * toString method
19207      * @method toString
19208      * @return {string} string representation of the dd obj
19209      */
19210     toString: function() {
19211         return ("DragDrop " + this.id);
19212     }
19213
19214 });
19215
19216 })();
19217 /*
19218  * Based on:
19219  * Ext JS Library 1.1.1
19220  * Copyright(c) 2006-2007, Ext JS, LLC.
19221  *
19222  * Originally Released Under LGPL - original licence link has changed is not relivant.
19223  *
19224  * Fork - LGPL
19225  * <script type="text/javascript">
19226  */
19227
19228
19229 /**
19230  * The drag and drop utility provides a framework for building drag and drop
19231  * applications.  In addition to enabling drag and drop for specific elements,
19232  * the drag and drop elements are tracked by the manager class, and the
19233  * interactions between the various elements are tracked during the drag and
19234  * the implementing code is notified about these important moments.
19235  */
19236
19237 // Only load the library once.  Rewriting the manager class would orphan
19238 // existing drag and drop instances.
19239 if (!Roo.dd.DragDropMgr) {
19240
19241 /**
19242  * @class Roo.dd.DragDropMgr
19243  * DragDropMgr is a singleton that tracks the element interaction for
19244  * all DragDrop items in the window.  Generally, you will not call
19245  * this class directly, but it does have helper methods that could
19246  * be useful in your DragDrop implementations.
19247  * @singleton
19248  */
19249 Roo.dd.DragDropMgr = function() {
19250
19251     var Event = Roo.EventManager;
19252
19253     return {
19254
19255         /**
19256          * Two dimensional Array of registered DragDrop objects.  The first
19257          * dimension is the DragDrop item group, the second the DragDrop
19258          * object.
19259          * @property ids
19260          * @type {string: string}
19261          * @private
19262          * @static
19263          */
19264         ids: {},
19265
19266         /**
19267          * Array of element ids defined as drag handles.  Used to determine
19268          * if the element that generated the mousedown event is actually the
19269          * handle and not the html element itself.
19270          * @property handleIds
19271          * @type {string: string}
19272          * @private
19273          * @static
19274          */
19275         handleIds: {},
19276
19277         /**
19278          * the DragDrop object that is currently being dragged
19279          * @property dragCurrent
19280          * @type DragDrop
19281          * @private
19282          * @static
19283          **/
19284         dragCurrent: null,
19285
19286         /**
19287          * the DragDrop object(s) that are being hovered over
19288          * @property dragOvers
19289          * @type Array
19290          * @private
19291          * @static
19292          */
19293         dragOvers: {},
19294
19295         /**
19296          * the X distance between the cursor and the object being dragged
19297          * @property deltaX
19298          * @type int
19299          * @private
19300          * @static
19301          */
19302         deltaX: 0,
19303
19304         /**
19305          * the Y distance between the cursor and the object being dragged
19306          * @property deltaY
19307          * @type int
19308          * @private
19309          * @static
19310          */
19311         deltaY: 0,
19312
19313         /**
19314          * Flag to determine if we should prevent the default behavior of the
19315          * events we define. By default this is true, but this can be set to
19316          * false if you need the default behavior (not recommended)
19317          * @property preventDefault
19318          * @type boolean
19319          * @static
19320          */
19321         preventDefault: true,
19322
19323         /**
19324          * Flag to determine if we should stop the propagation of the events
19325          * we generate. This is true by default but you may want to set it to
19326          * false if the html element contains other features that require the
19327          * mouse click.
19328          * @property stopPropagation
19329          * @type boolean
19330          * @static
19331          */
19332         stopPropagation: true,
19333
19334         /**
19335          * Internal flag that is set to true when drag and drop has been
19336          * intialized
19337          * @property initialized
19338          * @private
19339          * @static
19340          */
19341         initalized: false,
19342
19343         /**
19344          * All drag and drop can be disabled.
19345          * @property locked
19346          * @private
19347          * @static
19348          */
19349         locked: false,
19350
19351         /**
19352          * Called the first time an element is registered.
19353          * @method init
19354          * @private
19355          * @static
19356          */
19357         init: function() {
19358             this.initialized = true;
19359         },
19360
19361         /**
19362          * In point mode, drag and drop interaction is defined by the
19363          * location of the cursor during the drag/drop
19364          * @property POINT
19365          * @type int
19366          * @static
19367          */
19368         POINT: 0,
19369
19370         /**
19371          * In intersect mode, drag and drop interactio nis defined by the
19372          * overlap of two or more drag and drop objects.
19373          * @property INTERSECT
19374          * @type int
19375          * @static
19376          */
19377         INTERSECT: 1,
19378
19379         /**
19380          * The current drag and drop mode.  Default: POINT
19381          * @property mode
19382          * @type int
19383          * @static
19384          */
19385         mode: 0,
19386
19387         /**
19388          * Runs method on all drag and drop objects
19389          * @method _execOnAll
19390          * @private
19391          * @static
19392          */
19393         _execOnAll: function(sMethod, args) {
19394             for (var i in this.ids) {
19395                 for (var j in this.ids[i]) {
19396                     var oDD = this.ids[i][j];
19397                     if (! this.isTypeOfDD(oDD)) {
19398                         continue;
19399                     }
19400                     oDD[sMethod].apply(oDD, args);
19401                 }
19402             }
19403         },
19404
19405         /**
19406          * Drag and drop initialization.  Sets up the global event handlers
19407          * @method _onLoad
19408          * @private
19409          * @static
19410          */
19411         _onLoad: function() {
19412
19413             this.init();
19414
19415             if (!Roo.isTouch) {
19416                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19417                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19418             }
19419             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19420             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19421             
19422             Event.on(window,   "unload",    this._onUnload, this, true);
19423             Event.on(window,   "resize",    this._onResize, this, true);
19424             // Event.on(window,   "mouseout",    this._test);
19425
19426         },
19427
19428         /**
19429          * Reset constraints on all drag and drop objs
19430          * @method _onResize
19431          * @private
19432          * @static
19433          */
19434         _onResize: function(e) {
19435             this._execOnAll("resetConstraints", []);
19436         },
19437
19438         /**
19439          * Lock all drag and drop functionality
19440          * @method lock
19441          * @static
19442          */
19443         lock: function() { this.locked = true; },
19444
19445         /**
19446          * Unlock all drag and drop functionality
19447          * @method unlock
19448          * @static
19449          */
19450         unlock: function() { this.locked = false; },
19451
19452         /**
19453          * Is drag and drop locked?
19454          * @method isLocked
19455          * @return {boolean} True if drag and drop is locked, false otherwise.
19456          * @static
19457          */
19458         isLocked: function() { return this.locked; },
19459
19460         /**
19461          * Location cache that is set for all drag drop objects when a drag is
19462          * initiated, cleared when the drag is finished.
19463          * @property locationCache
19464          * @private
19465          * @static
19466          */
19467         locationCache: {},
19468
19469         /**
19470          * Set useCache to false if you want to force object the lookup of each
19471          * drag and drop linked element constantly during a drag.
19472          * @property useCache
19473          * @type boolean
19474          * @static
19475          */
19476         useCache: true,
19477
19478         /**
19479          * The number of pixels that the mouse needs to move after the
19480          * mousedown before the drag is initiated.  Default=3;
19481          * @property clickPixelThresh
19482          * @type int
19483          * @static
19484          */
19485         clickPixelThresh: 3,
19486
19487         /**
19488          * The number of milliseconds after the mousedown event to initiate the
19489          * drag if we don't get a mouseup event. Default=1000
19490          * @property clickTimeThresh
19491          * @type int
19492          * @static
19493          */
19494         clickTimeThresh: 350,
19495
19496         /**
19497          * Flag that indicates that either the drag pixel threshold or the
19498          * mousdown time threshold has been met
19499          * @property dragThreshMet
19500          * @type boolean
19501          * @private
19502          * @static
19503          */
19504         dragThreshMet: false,
19505
19506         /**
19507          * Timeout used for the click time threshold
19508          * @property clickTimeout
19509          * @type Object
19510          * @private
19511          * @static
19512          */
19513         clickTimeout: null,
19514
19515         /**
19516          * The X position of the mousedown event stored for later use when a
19517          * drag threshold is met.
19518          * @property startX
19519          * @type int
19520          * @private
19521          * @static
19522          */
19523         startX: 0,
19524
19525         /**
19526          * The Y position of the mousedown event stored for later use when a
19527          * drag threshold is met.
19528          * @property startY
19529          * @type int
19530          * @private
19531          * @static
19532          */
19533         startY: 0,
19534
19535         /**
19536          * Each DragDrop instance must be registered with the DragDropMgr.
19537          * This is executed in DragDrop.init()
19538          * @method regDragDrop
19539          * @param {DragDrop} oDD the DragDrop object to register
19540          * @param {String} sGroup the name of the group this element belongs to
19541          * @static
19542          */
19543         regDragDrop: function(oDD, sGroup) {
19544             if (!this.initialized) { this.init(); }
19545
19546             if (!this.ids[sGroup]) {
19547                 this.ids[sGroup] = {};
19548             }
19549             this.ids[sGroup][oDD.id] = oDD;
19550         },
19551
19552         /**
19553          * Removes the supplied dd instance from the supplied group. Executed
19554          * by DragDrop.removeFromGroup, so don't call this function directly.
19555          * @method removeDDFromGroup
19556          * @private
19557          * @static
19558          */
19559         removeDDFromGroup: function(oDD, sGroup) {
19560             if (!this.ids[sGroup]) {
19561                 this.ids[sGroup] = {};
19562             }
19563
19564             var obj = this.ids[sGroup];
19565             if (obj && obj[oDD.id]) {
19566                 delete obj[oDD.id];
19567             }
19568         },
19569
19570         /**
19571          * Unregisters a drag and drop item.  This is executed in
19572          * DragDrop.unreg, use that method instead of calling this directly.
19573          * @method _remove
19574          * @private
19575          * @static
19576          */
19577         _remove: function(oDD) {
19578             for (var g in oDD.groups) {
19579                 if (g && this.ids[g][oDD.id]) {
19580                     delete this.ids[g][oDD.id];
19581                 }
19582             }
19583             delete this.handleIds[oDD.id];
19584         },
19585
19586         /**
19587          * Each DragDrop handle element must be registered.  This is done
19588          * automatically when executing DragDrop.setHandleElId()
19589          * @method regHandle
19590          * @param {String} sDDId the DragDrop id this element is a handle for
19591          * @param {String} sHandleId the id of the element that is the drag
19592          * handle
19593          * @static
19594          */
19595         regHandle: function(sDDId, sHandleId) {
19596             if (!this.handleIds[sDDId]) {
19597                 this.handleIds[sDDId] = {};
19598             }
19599             this.handleIds[sDDId][sHandleId] = sHandleId;
19600         },
19601
19602         /**
19603          * Utility function to determine if a given element has been
19604          * registered as a drag drop item.
19605          * @method isDragDrop
19606          * @param {String} id the element id to check
19607          * @return {boolean} true if this element is a DragDrop item,
19608          * false otherwise
19609          * @static
19610          */
19611         isDragDrop: function(id) {
19612             return ( this.getDDById(id) ) ? true : false;
19613         },
19614
19615         /**
19616          * Returns the drag and drop instances that are in all groups the
19617          * passed in instance belongs to.
19618          * @method getRelated
19619          * @param {DragDrop} p_oDD the obj to get related data for
19620          * @param {boolean} bTargetsOnly if true, only return targetable objs
19621          * @return {DragDrop[]} the related instances
19622          * @static
19623          */
19624         getRelated: function(p_oDD, bTargetsOnly) {
19625             var oDDs = [];
19626             for (var i in p_oDD.groups) {
19627                 for (j in this.ids[i]) {
19628                     var dd = this.ids[i][j];
19629                     if (! this.isTypeOfDD(dd)) {
19630                         continue;
19631                     }
19632                     if (!bTargetsOnly || dd.isTarget) {
19633                         oDDs[oDDs.length] = dd;
19634                     }
19635                 }
19636             }
19637
19638             return oDDs;
19639         },
19640
19641         /**
19642          * Returns true if the specified dd target is a legal target for
19643          * the specifice drag obj
19644          * @method isLegalTarget
19645          * @param {DragDrop} the drag obj
19646          * @param {DragDrop} the target
19647          * @return {boolean} true if the target is a legal target for the
19648          * dd obj
19649          * @static
19650          */
19651         isLegalTarget: function (oDD, oTargetDD) {
19652             var targets = this.getRelated(oDD, true);
19653             for (var i=0, len=targets.length;i<len;++i) {
19654                 if (targets[i].id == oTargetDD.id) {
19655                     return true;
19656                 }
19657             }
19658
19659             return false;
19660         },
19661
19662         /**
19663          * My goal is to be able to transparently determine if an object is
19664          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19665          * returns "object", oDD.constructor.toString() always returns
19666          * "DragDrop" and not the name of the subclass.  So for now it just
19667          * evaluates a well-known variable in DragDrop.
19668          * @method isTypeOfDD
19669          * @param {Object} the object to evaluate
19670          * @return {boolean} true if typeof oDD = DragDrop
19671          * @static
19672          */
19673         isTypeOfDD: function (oDD) {
19674             return (oDD && oDD.__ygDragDrop);
19675         },
19676
19677         /**
19678          * Utility function to determine if a given element has been
19679          * registered as a drag drop handle for the given Drag Drop object.
19680          * @method isHandle
19681          * @param {String} id the element id to check
19682          * @return {boolean} true if this element is a DragDrop handle, false
19683          * otherwise
19684          * @static
19685          */
19686         isHandle: function(sDDId, sHandleId) {
19687             return ( this.handleIds[sDDId] &&
19688                             this.handleIds[sDDId][sHandleId] );
19689         },
19690
19691         /**
19692          * Returns the DragDrop instance for a given id
19693          * @method getDDById
19694          * @param {String} id the id of the DragDrop object
19695          * @return {DragDrop} the drag drop object, null if it is not found
19696          * @static
19697          */
19698         getDDById: function(id) {
19699             for (var i in this.ids) {
19700                 if (this.ids[i][id]) {
19701                     return this.ids[i][id];
19702                 }
19703             }
19704             return null;
19705         },
19706
19707         /**
19708          * Fired after a registered DragDrop object gets the mousedown event.
19709          * Sets up the events required to track the object being dragged
19710          * @method handleMouseDown
19711          * @param {Event} e the event
19712          * @param oDD the DragDrop object being dragged
19713          * @private
19714          * @static
19715          */
19716         handleMouseDown: function(e, oDD) {
19717             if(Roo.QuickTips){
19718                 Roo.QuickTips.disable();
19719             }
19720             this.currentTarget = e.getTarget();
19721
19722             this.dragCurrent = oDD;
19723
19724             var el = oDD.getEl();
19725
19726             // track start position
19727             this.startX = e.getPageX();
19728             this.startY = e.getPageY();
19729
19730             this.deltaX = this.startX - el.offsetLeft;
19731             this.deltaY = this.startY - el.offsetTop;
19732
19733             this.dragThreshMet = false;
19734
19735             this.clickTimeout = setTimeout(
19736                     function() {
19737                         var DDM = Roo.dd.DDM;
19738                         DDM.startDrag(DDM.startX, DDM.startY);
19739                     },
19740                     this.clickTimeThresh );
19741         },
19742
19743         /**
19744          * Fired when either the drag pixel threshol or the mousedown hold
19745          * time threshold has been met.
19746          * @method startDrag
19747          * @param x {int} the X position of the original mousedown
19748          * @param y {int} the Y position of the original mousedown
19749          * @static
19750          */
19751         startDrag: function(x, y) {
19752             clearTimeout(this.clickTimeout);
19753             if (this.dragCurrent) {
19754                 this.dragCurrent.b4StartDrag(x, y);
19755                 this.dragCurrent.startDrag(x, y);
19756             }
19757             this.dragThreshMet = true;
19758         },
19759
19760         /**
19761          * Internal function to handle the mouseup event.  Will be invoked
19762          * from the context of the document.
19763          * @method handleMouseUp
19764          * @param {Event} e the event
19765          * @private
19766          * @static
19767          */
19768         handleMouseUp: function(e) {
19769
19770             if(Roo.QuickTips){
19771                 Roo.QuickTips.enable();
19772             }
19773             if (! this.dragCurrent) {
19774                 return;
19775             }
19776
19777             clearTimeout(this.clickTimeout);
19778
19779             if (this.dragThreshMet) {
19780                 this.fireEvents(e, true);
19781             } else {
19782             }
19783
19784             this.stopDrag(e);
19785
19786             this.stopEvent(e);
19787         },
19788
19789         /**
19790          * Utility to stop event propagation and event default, if these
19791          * features are turned on.
19792          * @method stopEvent
19793          * @param {Event} e the event as returned by this.getEvent()
19794          * @static
19795          */
19796         stopEvent: function(e){
19797             if(this.stopPropagation) {
19798                 e.stopPropagation();
19799             }
19800
19801             if (this.preventDefault) {
19802                 e.preventDefault();
19803             }
19804         },
19805
19806         /**
19807          * Internal function to clean up event handlers after the drag
19808          * operation is complete
19809          * @method stopDrag
19810          * @param {Event} e the event
19811          * @private
19812          * @static
19813          */
19814         stopDrag: function(e) {
19815             // Fire the drag end event for the item that was dragged
19816             if (this.dragCurrent) {
19817                 if (this.dragThreshMet) {
19818                     this.dragCurrent.b4EndDrag(e);
19819                     this.dragCurrent.endDrag(e);
19820                 }
19821
19822                 this.dragCurrent.onMouseUp(e);
19823             }
19824
19825             this.dragCurrent = null;
19826             this.dragOvers = {};
19827         },
19828
19829         /**
19830          * Internal function to handle the mousemove event.  Will be invoked
19831          * from the context of the html element.
19832          *
19833          * @TODO figure out what we can do about mouse events lost when the
19834          * user drags objects beyond the window boundary.  Currently we can
19835          * detect this in internet explorer by verifying that the mouse is
19836          * down during the mousemove event.  Firefox doesn't give us the
19837          * button state on the mousemove event.
19838          * @method handleMouseMove
19839          * @param {Event} e the event
19840          * @private
19841          * @static
19842          */
19843         handleMouseMove: function(e) {
19844             if (! this.dragCurrent) {
19845                 return true;
19846             }
19847
19848             // var button = e.which || e.button;
19849
19850             // check for IE mouseup outside of page boundary
19851             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19852                 this.stopEvent(e);
19853                 return this.handleMouseUp(e);
19854             }
19855
19856             if (!this.dragThreshMet) {
19857                 var diffX = Math.abs(this.startX - e.getPageX());
19858                 var diffY = Math.abs(this.startY - e.getPageY());
19859                 if (diffX > this.clickPixelThresh ||
19860                             diffY > this.clickPixelThresh) {
19861                     this.startDrag(this.startX, this.startY);
19862                 }
19863             }
19864
19865             if (this.dragThreshMet) {
19866                 this.dragCurrent.b4Drag(e);
19867                 this.dragCurrent.onDrag(e);
19868                 if(!this.dragCurrent.moveOnly){
19869                     this.fireEvents(e, false);
19870                 }
19871             }
19872
19873             this.stopEvent(e);
19874
19875             return true;
19876         },
19877
19878         /**
19879          * Iterates over all of the DragDrop elements to find ones we are
19880          * hovering over or dropping on
19881          * @method fireEvents
19882          * @param {Event} e the event
19883          * @param {boolean} isDrop is this a drop op or a mouseover op?
19884          * @private
19885          * @static
19886          */
19887         fireEvents: function(e, isDrop) {
19888             var dc = this.dragCurrent;
19889
19890             // If the user did the mouse up outside of the window, we could
19891             // get here even though we have ended the drag.
19892             if (!dc || dc.isLocked()) {
19893                 return;
19894             }
19895
19896             var pt = e.getPoint();
19897
19898             // cache the previous dragOver array
19899             var oldOvers = [];
19900
19901             var outEvts   = [];
19902             var overEvts  = [];
19903             var dropEvts  = [];
19904             var enterEvts = [];
19905
19906             // Check to see if the object(s) we were hovering over is no longer
19907             // being hovered over so we can fire the onDragOut event
19908             for (var i in this.dragOvers) {
19909
19910                 var ddo = this.dragOvers[i];
19911
19912                 if (! this.isTypeOfDD(ddo)) {
19913                     continue;
19914                 }
19915
19916                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19917                     outEvts.push( ddo );
19918                 }
19919
19920                 oldOvers[i] = true;
19921                 delete this.dragOvers[i];
19922             }
19923
19924             for (var sGroup in dc.groups) {
19925
19926                 if ("string" != typeof sGroup) {
19927                     continue;
19928                 }
19929
19930                 for (i in this.ids[sGroup]) {
19931                     var oDD = this.ids[sGroup][i];
19932                     if (! this.isTypeOfDD(oDD)) {
19933                         continue;
19934                     }
19935
19936                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19937                         if (this.isOverTarget(pt, oDD, this.mode)) {
19938                             // look for drop interactions
19939                             if (isDrop) {
19940                                 dropEvts.push( oDD );
19941                             // look for drag enter and drag over interactions
19942                             } else {
19943
19944                                 // initial drag over: dragEnter fires
19945                                 if (!oldOvers[oDD.id]) {
19946                                     enterEvts.push( oDD );
19947                                 // subsequent drag overs: dragOver fires
19948                                 } else {
19949                                     overEvts.push( oDD );
19950                                 }
19951
19952                                 this.dragOvers[oDD.id] = oDD;
19953                             }
19954                         }
19955                     }
19956                 }
19957             }
19958
19959             if (this.mode) {
19960                 if (outEvts.length) {
19961                     dc.b4DragOut(e, outEvts);
19962                     dc.onDragOut(e, outEvts);
19963                 }
19964
19965                 if (enterEvts.length) {
19966                     dc.onDragEnter(e, enterEvts);
19967                 }
19968
19969                 if (overEvts.length) {
19970                     dc.b4DragOver(e, overEvts);
19971                     dc.onDragOver(e, overEvts);
19972                 }
19973
19974                 if (dropEvts.length) {
19975                     dc.b4DragDrop(e, dropEvts);
19976                     dc.onDragDrop(e, dropEvts);
19977                 }
19978
19979             } else {
19980                 // fire dragout events
19981                 var len = 0;
19982                 for (i=0, len=outEvts.length; i<len; ++i) {
19983                     dc.b4DragOut(e, outEvts[i].id);
19984                     dc.onDragOut(e, outEvts[i].id);
19985                 }
19986
19987                 // fire enter events
19988                 for (i=0,len=enterEvts.length; i<len; ++i) {
19989                     // dc.b4DragEnter(e, oDD.id);
19990                     dc.onDragEnter(e, enterEvts[i].id);
19991                 }
19992
19993                 // fire over events
19994                 for (i=0,len=overEvts.length; i<len; ++i) {
19995                     dc.b4DragOver(e, overEvts[i].id);
19996                     dc.onDragOver(e, overEvts[i].id);
19997                 }
19998
19999                 // fire drop events
20000                 for (i=0, len=dropEvts.length; i<len; ++i) {
20001                     dc.b4DragDrop(e, dropEvts[i].id);
20002                     dc.onDragDrop(e, dropEvts[i].id);
20003                 }
20004
20005             }
20006
20007             // notify about a drop that did not find a target
20008             if (isDrop && !dropEvts.length) {
20009                 dc.onInvalidDrop(e);
20010             }
20011
20012         },
20013
20014         /**
20015          * Helper function for getting the best match from the list of drag
20016          * and drop objects returned by the drag and drop events when we are
20017          * in INTERSECT mode.  It returns either the first object that the
20018          * cursor is over, or the object that has the greatest overlap with
20019          * the dragged element.
20020          * @method getBestMatch
20021          * @param  {DragDrop[]} dds The array of drag and drop objects
20022          * targeted
20023          * @return {DragDrop}       The best single match
20024          * @static
20025          */
20026         getBestMatch: function(dds) {
20027             var winner = null;
20028             // Return null if the input is not what we expect
20029             //if (!dds || !dds.length || dds.length == 0) {
20030                // winner = null;
20031             // If there is only one item, it wins
20032             //} else if (dds.length == 1) {
20033
20034             var len = dds.length;
20035
20036             if (len == 1) {
20037                 winner = dds[0];
20038             } else {
20039                 // Loop through the targeted items
20040                 for (var i=0; i<len; ++i) {
20041                     var dd = dds[i];
20042                     // If the cursor is over the object, it wins.  If the
20043                     // cursor is over multiple matches, the first one we come
20044                     // to wins.
20045                     if (dd.cursorIsOver) {
20046                         winner = dd;
20047                         break;
20048                     // Otherwise the object with the most overlap wins
20049                     } else {
20050                         if (!winner ||
20051                             winner.overlap.getArea() < dd.overlap.getArea()) {
20052                             winner = dd;
20053                         }
20054                     }
20055                 }
20056             }
20057
20058             return winner;
20059         },
20060
20061         /**
20062          * Refreshes the cache of the top-left and bottom-right points of the
20063          * drag and drop objects in the specified group(s).  This is in the
20064          * format that is stored in the drag and drop instance, so typical
20065          * usage is:
20066          * <code>
20067          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20068          * </code>
20069          * Alternatively:
20070          * <code>
20071          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20072          * </code>
20073          * @TODO this really should be an indexed array.  Alternatively this
20074          * method could accept both.
20075          * @method refreshCache
20076          * @param {Object} groups an associative array of groups to refresh
20077          * @static
20078          */
20079         refreshCache: function(groups) {
20080             for (var sGroup in groups) {
20081                 if ("string" != typeof sGroup) {
20082                     continue;
20083                 }
20084                 for (var i in this.ids[sGroup]) {
20085                     var oDD = this.ids[sGroup][i];
20086
20087                     if (this.isTypeOfDD(oDD)) {
20088                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20089                         var loc = this.getLocation(oDD);
20090                         if (loc) {
20091                             this.locationCache[oDD.id] = loc;
20092                         } else {
20093                             delete this.locationCache[oDD.id];
20094                             // this will unregister the drag and drop object if
20095                             // the element is not in a usable state
20096                             // oDD.unreg();
20097                         }
20098                     }
20099                 }
20100             }
20101         },
20102
20103         /**
20104          * This checks to make sure an element exists and is in the DOM.  The
20105          * main purpose is to handle cases where innerHTML is used to remove
20106          * drag and drop objects from the DOM.  IE provides an 'unspecified
20107          * error' when trying to access the offsetParent of such an element
20108          * @method verifyEl
20109          * @param {HTMLElement} el the element to check
20110          * @return {boolean} true if the element looks usable
20111          * @static
20112          */
20113         verifyEl: function(el) {
20114             if (el) {
20115                 var parent;
20116                 if(Roo.isIE){
20117                     try{
20118                         parent = el.offsetParent;
20119                     }catch(e){}
20120                 }else{
20121                     parent = el.offsetParent;
20122                 }
20123                 if (parent) {
20124                     return true;
20125                 }
20126             }
20127
20128             return false;
20129         },
20130
20131         /**
20132          * Returns a Region object containing the drag and drop element's position
20133          * and size, including the padding configured for it
20134          * @method getLocation
20135          * @param {DragDrop} oDD the drag and drop object to get the
20136          *                       location for
20137          * @return {Roo.lib.Region} a Region object representing the total area
20138          *                             the element occupies, including any padding
20139          *                             the instance is configured for.
20140          * @static
20141          */
20142         getLocation: function(oDD) {
20143             if (! this.isTypeOfDD(oDD)) {
20144                 return null;
20145             }
20146
20147             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20148
20149             try {
20150                 pos= Roo.lib.Dom.getXY(el);
20151             } catch (e) { }
20152
20153             if (!pos) {
20154                 return null;
20155             }
20156
20157             x1 = pos[0];
20158             x2 = x1 + el.offsetWidth;
20159             y1 = pos[1];
20160             y2 = y1 + el.offsetHeight;
20161
20162             t = y1 - oDD.padding[0];
20163             r = x2 + oDD.padding[1];
20164             b = y2 + oDD.padding[2];
20165             l = x1 - oDD.padding[3];
20166
20167             return new Roo.lib.Region( t, r, b, l );
20168         },
20169
20170         /**
20171          * Checks the cursor location to see if it over the target
20172          * @method isOverTarget
20173          * @param {Roo.lib.Point} pt The point to evaluate
20174          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20175          * @return {boolean} true if the mouse is over the target
20176          * @private
20177          * @static
20178          */
20179         isOverTarget: function(pt, oTarget, intersect) {
20180             // use cache if available
20181             var loc = this.locationCache[oTarget.id];
20182             if (!loc || !this.useCache) {
20183                 loc = this.getLocation(oTarget);
20184                 this.locationCache[oTarget.id] = loc;
20185
20186             }
20187
20188             if (!loc) {
20189                 return false;
20190             }
20191
20192             oTarget.cursorIsOver = loc.contains( pt );
20193
20194             // DragDrop is using this as a sanity check for the initial mousedown
20195             // in this case we are done.  In POINT mode, if the drag obj has no
20196             // contraints, we are also done. Otherwise we need to evaluate the
20197             // location of the target as related to the actual location of the
20198             // dragged element.
20199             var dc = this.dragCurrent;
20200             if (!dc || !dc.getTargetCoord ||
20201                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20202                 return oTarget.cursorIsOver;
20203             }
20204
20205             oTarget.overlap = null;
20206
20207             // Get the current location of the drag element, this is the
20208             // location of the mouse event less the delta that represents
20209             // where the original mousedown happened on the element.  We
20210             // need to consider constraints and ticks as well.
20211             var pos = dc.getTargetCoord(pt.x, pt.y);
20212
20213             var el = dc.getDragEl();
20214             var curRegion = new Roo.lib.Region( pos.y,
20215                                                    pos.x + el.offsetWidth,
20216                                                    pos.y + el.offsetHeight,
20217                                                    pos.x );
20218
20219             var overlap = curRegion.intersect(loc);
20220
20221             if (overlap) {
20222                 oTarget.overlap = overlap;
20223                 return (intersect) ? true : oTarget.cursorIsOver;
20224             } else {
20225                 return false;
20226             }
20227         },
20228
20229         /**
20230          * unload event handler
20231          * @method _onUnload
20232          * @private
20233          * @static
20234          */
20235         _onUnload: function(e, me) {
20236             Roo.dd.DragDropMgr.unregAll();
20237         },
20238
20239         /**
20240          * Cleans up the drag and drop events and objects.
20241          * @method unregAll
20242          * @private
20243          * @static
20244          */
20245         unregAll: function() {
20246
20247             if (this.dragCurrent) {
20248                 this.stopDrag();
20249                 this.dragCurrent = null;
20250             }
20251
20252             this._execOnAll("unreg", []);
20253
20254             for (i in this.elementCache) {
20255                 delete this.elementCache[i];
20256             }
20257
20258             this.elementCache = {};
20259             this.ids = {};
20260         },
20261
20262         /**
20263          * A cache of DOM elements
20264          * @property elementCache
20265          * @private
20266          * @static
20267          */
20268         elementCache: {},
20269
20270         /**
20271          * Get the wrapper for the DOM element specified
20272          * @method getElWrapper
20273          * @param {String} id the id of the element to get
20274          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20275          * @private
20276          * @deprecated This wrapper isn't that useful
20277          * @static
20278          */
20279         getElWrapper: function(id) {
20280             var oWrapper = this.elementCache[id];
20281             if (!oWrapper || !oWrapper.el) {
20282                 oWrapper = this.elementCache[id] =
20283                     new this.ElementWrapper(Roo.getDom(id));
20284             }
20285             return oWrapper;
20286         },
20287
20288         /**
20289          * Returns the actual DOM element
20290          * @method getElement
20291          * @param {String} id the id of the elment to get
20292          * @return {Object} The element
20293          * @deprecated use Roo.getDom instead
20294          * @static
20295          */
20296         getElement: function(id) {
20297             return Roo.getDom(id);
20298         },
20299
20300         /**
20301          * Returns the style property for the DOM element (i.e.,
20302          * document.getElById(id).style)
20303          * @method getCss
20304          * @param {String} id the id of the elment to get
20305          * @return {Object} The style property of the element
20306          * @deprecated use Roo.getDom instead
20307          * @static
20308          */
20309         getCss: function(id) {
20310             var el = Roo.getDom(id);
20311             return (el) ? el.style : null;
20312         },
20313
20314         /**
20315          * Inner class for cached elements
20316          * @class DragDropMgr.ElementWrapper
20317          * @for DragDropMgr
20318          * @private
20319          * @deprecated
20320          */
20321         ElementWrapper: function(el) {
20322                 /**
20323                  * The element
20324                  * @property el
20325                  */
20326                 this.el = el || null;
20327                 /**
20328                  * The element id
20329                  * @property id
20330                  */
20331                 this.id = this.el && el.id;
20332                 /**
20333                  * A reference to the style property
20334                  * @property css
20335                  */
20336                 this.css = this.el && el.style;
20337             },
20338
20339         /**
20340          * Returns the X position of an html element
20341          * @method getPosX
20342          * @param el the element for which to get the position
20343          * @return {int} the X coordinate
20344          * @for DragDropMgr
20345          * @deprecated use Roo.lib.Dom.getX instead
20346          * @static
20347          */
20348         getPosX: function(el) {
20349             return Roo.lib.Dom.getX(el);
20350         },
20351
20352         /**
20353          * Returns the Y position of an html element
20354          * @method getPosY
20355          * @param el the element for which to get the position
20356          * @return {int} the Y coordinate
20357          * @deprecated use Roo.lib.Dom.getY instead
20358          * @static
20359          */
20360         getPosY: function(el) {
20361             return Roo.lib.Dom.getY(el);
20362         },
20363
20364         /**
20365          * Swap two nodes.  In IE, we use the native method, for others we
20366          * emulate the IE behavior
20367          * @method swapNode
20368          * @param n1 the first node to swap
20369          * @param n2 the other node to swap
20370          * @static
20371          */
20372         swapNode: function(n1, n2) {
20373             if (n1.swapNode) {
20374                 n1.swapNode(n2);
20375             } else {
20376                 var p = n2.parentNode;
20377                 var s = n2.nextSibling;
20378
20379                 if (s == n1) {
20380                     p.insertBefore(n1, n2);
20381                 } else if (n2 == n1.nextSibling) {
20382                     p.insertBefore(n2, n1);
20383                 } else {
20384                     n1.parentNode.replaceChild(n2, n1);
20385                     p.insertBefore(n1, s);
20386                 }
20387             }
20388         },
20389
20390         /**
20391          * Returns the current scroll position
20392          * @method getScroll
20393          * @private
20394          * @static
20395          */
20396         getScroll: function () {
20397             var t, l, dde=document.documentElement, db=document.body;
20398             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20399                 t = dde.scrollTop;
20400                 l = dde.scrollLeft;
20401             } else if (db) {
20402                 t = db.scrollTop;
20403                 l = db.scrollLeft;
20404             } else {
20405
20406             }
20407             return { top: t, left: l };
20408         },
20409
20410         /**
20411          * Returns the specified element style property
20412          * @method getStyle
20413          * @param {HTMLElement} el          the element
20414          * @param {string}      styleProp   the style property
20415          * @return {string} The value of the style property
20416          * @deprecated use Roo.lib.Dom.getStyle
20417          * @static
20418          */
20419         getStyle: function(el, styleProp) {
20420             return Roo.fly(el).getStyle(styleProp);
20421         },
20422
20423         /**
20424          * Gets the scrollTop
20425          * @method getScrollTop
20426          * @return {int} the document's scrollTop
20427          * @static
20428          */
20429         getScrollTop: function () { return this.getScroll().top; },
20430
20431         /**
20432          * Gets the scrollLeft
20433          * @method getScrollLeft
20434          * @return {int} the document's scrollTop
20435          * @static
20436          */
20437         getScrollLeft: function () { return this.getScroll().left; },
20438
20439         /**
20440          * Sets the x/y position of an element to the location of the
20441          * target element.
20442          * @method moveToEl
20443          * @param {HTMLElement} moveEl      The element to move
20444          * @param {HTMLElement} targetEl    The position reference element
20445          * @static
20446          */
20447         moveToEl: function (moveEl, targetEl) {
20448             var aCoord = Roo.lib.Dom.getXY(targetEl);
20449             Roo.lib.Dom.setXY(moveEl, aCoord);
20450         },
20451
20452         /**
20453          * Numeric array sort function
20454          * @method numericSort
20455          * @static
20456          */
20457         numericSort: function(a, b) { return (a - b); },
20458
20459         /**
20460          * Internal counter
20461          * @property _timeoutCount
20462          * @private
20463          * @static
20464          */
20465         _timeoutCount: 0,
20466
20467         /**
20468          * Trying to make the load order less important.  Without this we get
20469          * an error if this file is loaded before the Event Utility.
20470          * @method _addListeners
20471          * @private
20472          * @static
20473          */
20474         _addListeners: function() {
20475             var DDM = Roo.dd.DDM;
20476             if ( Roo.lib.Event && document ) {
20477                 DDM._onLoad();
20478             } else {
20479                 if (DDM._timeoutCount > 2000) {
20480                 } else {
20481                     setTimeout(DDM._addListeners, 10);
20482                     if (document && document.body) {
20483                         DDM._timeoutCount += 1;
20484                     }
20485                 }
20486             }
20487         },
20488
20489         /**
20490          * Recursively searches the immediate parent and all child nodes for
20491          * the handle element in order to determine wheter or not it was
20492          * clicked.
20493          * @method handleWasClicked
20494          * @param node the html element to inspect
20495          * @static
20496          */
20497         handleWasClicked: function(node, id) {
20498             if (this.isHandle(id, node.id)) {
20499                 return true;
20500             } else {
20501                 // check to see if this is a text node child of the one we want
20502                 var p = node.parentNode;
20503
20504                 while (p) {
20505                     if (this.isHandle(id, p.id)) {
20506                         return true;
20507                     } else {
20508                         p = p.parentNode;
20509                     }
20510                 }
20511             }
20512
20513             return false;
20514         }
20515
20516     };
20517
20518 }();
20519
20520 // shorter alias, save a few bytes
20521 Roo.dd.DDM = Roo.dd.DragDropMgr;
20522 Roo.dd.DDM._addListeners();
20523
20524 }/*
20525  * Based on:
20526  * Ext JS Library 1.1.1
20527  * Copyright(c) 2006-2007, Ext JS, LLC.
20528  *
20529  * Originally Released Under LGPL - original licence link has changed is not relivant.
20530  *
20531  * Fork - LGPL
20532  * <script type="text/javascript">
20533  */
20534
20535 /**
20536  * @class Roo.dd.DD
20537  * A DragDrop implementation where the linked element follows the
20538  * mouse cursor during a drag.
20539  * @extends Roo.dd.DragDrop
20540  * @constructor
20541  * @param {String} id the id of the linked element
20542  * @param {String} sGroup the group of related DragDrop items
20543  * @param {object} config an object containing configurable attributes
20544  *                Valid properties for DD:
20545  *                    scroll
20546  */
20547 Roo.dd.DD = function(id, sGroup, config) {
20548     if (id) {
20549         this.init(id, sGroup, config);
20550     }
20551 };
20552
20553 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20554
20555     /**
20556      * When set to true, the utility automatically tries to scroll the browser
20557      * window wehn a drag and drop element is dragged near the viewport boundary.
20558      * Defaults to true.
20559      * @property scroll
20560      * @type boolean
20561      */
20562     scroll: true,
20563
20564     /**
20565      * Sets the pointer offset to the distance between the linked element's top
20566      * left corner and the location the element was clicked
20567      * @method autoOffset
20568      * @param {int} iPageX the X coordinate of the click
20569      * @param {int} iPageY the Y coordinate of the click
20570      */
20571     autoOffset: function(iPageX, iPageY) {
20572         var x = iPageX - this.startPageX;
20573         var y = iPageY - this.startPageY;
20574         this.setDelta(x, y);
20575     },
20576
20577     /**
20578      * Sets the pointer offset.  You can call this directly to force the
20579      * offset to be in a particular location (e.g., pass in 0,0 to set it
20580      * to the center of the object)
20581      * @method setDelta
20582      * @param {int} iDeltaX the distance from the left
20583      * @param {int} iDeltaY the distance from the top
20584      */
20585     setDelta: function(iDeltaX, iDeltaY) {
20586         this.deltaX = iDeltaX;
20587         this.deltaY = iDeltaY;
20588     },
20589
20590     /**
20591      * Sets the drag element to the location of the mousedown or click event,
20592      * maintaining the cursor location relative to the location on the element
20593      * that was clicked.  Override this if you want to place the element in a
20594      * location other than where the cursor is.
20595      * @method setDragElPos
20596      * @param {int} iPageX the X coordinate of the mousedown or drag event
20597      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20598      */
20599     setDragElPos: function(iPageX, iPageY) {
20600         // the first time we do this, we are going to check to make sure
20601         // the element has css positioning
20602
20603         var el = this.getDragEl();
20604         this.alignElWithMouse(el, iPageX, iPageY);
20605     },
20606
20607     /**
20608      * Sets the element to the location of the mousedown or click event,
20609      * maintaining the cursor location relative to the location on the element
20610      * that was clicked.  Override this if you want to place the element in a
20611      * location other than where the cursor is.
20612      * @method alignElWithMouse
20613      * @param {HTMLElement} el the element to move
20614      * @param {int} iPageX the X coordinate of the mousedown or drag event
20615      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20616      */
20617     alignElWithMouse: function(el, iPageX, iPageY) {
20618         var oCoord = this.getTargetCoord(iPageX, iPageY);
20619         var fly = el.dom ? el : Roo.fly(el);
20620         if (!this.deltaSetXY) {
20621             var aCoord = [oCoord.x, oCoord.y];
20622             fly.setXY(aCoord);
20623             var newLeft = fly.getLeft(true);
20624             var newTop  = fly.getTop(true);
20625             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20626         } else {
20627             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20628         }
20629
20630         this.cachePosition(oCoord.x, oCoord.y);
20631         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20632         return oCoord;
20633     },
20634
20635     /**
20636      * Saves the most recent position so that we can reset the constraints and
20637      * tick marks on-demand.  We need to know this so that we can calculate the
20638      * number of pixels the element is offset from its original position.
20639      * @method cachePosition
20640      * @param iPageX the current x position (optional, this just makes it so we
20641      * don't have to look it up again)
20642      * @param iPageY the current y position (optional, this just makes it so we
20643      * don't have to look it up again)
20644      */
20645     cachePosition: function(iPageX, iPageY) {
20646         if (iPageX) {
20647             this.lastPageX = iPageX;
20648             this.lastPageY = iPageY;
20649         } else {
20650             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20651             this.lastPageX = aCoord[0];
20652             this.lastPageY = aCoord[1];
20653         }
20654     },
20655
20656     /**
20657      * Auto-scroll the window if the dragged object has been moved beyond the
20658      * visible window boundary.
20659      * @method autoScroll
20660      * @param {int} x the drag element's x position
20661      * @param {int} y the drag element's y position
20662      * @param {int} h the height of the drag element
20663      * @param {int} w the width of the drag element
20664      * @private
20665      */
20666     autoScroll: function(x, y, h, w) {
20667
20668         if (this.scroll) {
20669             // The client height
20670             var clientH = Roo.lib.Dom.getViewWidth();
20671
20672             // The client width
20673             var clientW = Roo.lib.Dom.getViewHeight();
20674
20675             // The amt scrolled down
20676             var st = this.DDM.getScrollTop();
20677
20678             // The amt scrolled right
20679             var sl = this.DDM.getScrollLeft();
20680
20681             // Location of the bottom of the element
20682             var bot = h + y;
20683
20684             // Location of the right of the element
20685             var right = w + x;
20686
20687             // The distance from the cursor to the bottom of the visible area,
20688             // adjusted so that we don't scroll if the cursor is beyond the
20689             // element drag constraints
20690             var toBot = (clientH + st - y - this.deltaY);
20691
20692             // The distance from the cursor to the right of the visible area
20693             var toRight = (clientW + sl - x - this.deltaX);
20694
20695
20696             // How close to the edge the cursor must be before we scroll
20697             // var thresh = (document.all) ? 100 : 40;
20698             var thresh = 40;
20699
20700             // How many pixels to scroll per autoscroll op.  This helps to reduce
20701             // clunky scrolling. IE is more sensitive about this ... it needs this
20702             // value to be higher.
20703             var scrAmt = (document.all) ? 80 : 30;
20704
20705             // Scroll down if we are near the bottom of the visible page and the
20706             // obj extends below the crease
20707             if ( bot > clientH && toBot < thresh ) {
20708                 window.scrollTo(sl, st + scrAmt);
20709             }
20710
20711             // Scroll up if the window is scrolled down and the top of the object
20712             // goes above the top border
20713             if ( y < st && st > 0 && y - st < thresh ) {
20714                 window.scrollTo(sl, st - scrAmt);
20715             }
20716
20717             // Scroll right if the obj is beyond the right border and the cursor is
20718             // near the border.
20719             if ( right > clientW && toRight < thresh ) {
20720                 window.scrollTo(sl + scrAmt, st);
20721             }
20722
20723             // Scroll left if the window has been scrolled to the right and the obj
20724             // extends past the left border
20725             if ( x < sl && sl > 0 && x - sl < thresh ) {
20726                 window.scrollTo(sl - scrAmt, st);
20727             }
20728         }
20729     },
20730
20731     /**
20732      * Finds the location the element should be placed if we want to move
20733      * it to where the mouse location less the click offset would place us.
20734      * @method getTargetCoord
20735      * @param {int} iPageX the X coordinate of the click
20736      * @param {int} iPageY the Y coordinate of the click
20737      * @return an object that contains the coordinates (Object.x and Object.y)
20738      * @private
20739      */
20740     getTargetCoord: function(iPageX, iPageY) {
20741
20742
20743         var x = iPageX - this.deltaX;
20744         var y = iPageY - this.deltaY;
20745
20746         if (this.constrainX) {
20747             if (x < this.minX) { x = this.minX; }
20748             if (x > this.maxX) { x = this.maxX; }
20749         }
20750
20751         if (this.constrainY) {
20752             if (y < this.minY) { y = this.minY; }
20753             if (y > this.maxY) { y = this.maxY; }
20754         }
20755
20756         x = this.getTick(x, this.xTicks);
20757         y = this.getTick(y, this.yTicks);
20758
20759
20760         return {x:x, y:y};
20761     },
20762
20763     /*
20764      * Sets up config options specific to this class. Overrides
20765      * Roo.dd.DragDrop, but all versions of this method through the
20766      * inheritance chain are called
20767      */
20768     applyConfig: function() {
20769         Roo.dd.DD.superclass.applyConfig.call(this);
20770         this.scroll = (this.config.scroll !== false);
20771     },
20772
20773     /*
20774      * Event that fires prior to the onMouseDown event.  Overrides
20775      * Roo.dd.DragDrop.
20776      */
20777     b4MouseDown: function(e) {
20778         // this.resetConstraints();
20779         this.autoOffset(e.getPageX(),
20780                             e.getPageY());
20781     },
20782
20783     /*
20784      * Event that fires prior to the onDrag event.  Overrides
20785      * Roo.dd.DragDrop.
20786      */
20787     b4Drag: function(e) {
20788         this.setDragElPos(e.getPageX(),
20789                             e.getPageY());
20790     },
20791
20792     toString: function() {
20793         return ("DD " + this.id);
20794     }
20795
20796     //////////////////////////////////////////////////////////////////////////
20797     // Debugging ygDragDrop events that can be overridden
20798     //////////////////////////////////////////////////////////////////////////
20799     /*
20800     startDrag: function(x, y) {
20801     },
20802
20803     onDrag: function(e) {
20804     },
20805
20806     onDragEnter: function(e, id) {
20807     },
20808
20809     onDragOver: function(e, id) {
20810     },
20811
20812     onDragOut: function(e, id) {
20813     },
20814
20815     onDragDrop: function(e, id) {
20816     },
20817
20818     endDrag: function(e) {
20819     }
20820
20821     */
20822
20823 });/*
20824  * Based on:
20825  * Ext JS Library 1.1.1
20826  * Copyright(c) 2006-2007, Ext JS, LLC.
20827  *
20828  * Originally Released Under LGPL - original licence link has changed is not relivant.
20829  *
20830  * Fork - LGPL
20831  * <script type="text/javascript">
20832  */
20833
20834 /**
20835  * @class Roo.dd.DDProxy
20836  * A DragDrop implementation that inserts an empty, bordered div into
20837  * the document that follows the cursor during drag operations.  At the time of
20838  * the click, the frame div is resized to the dimensions of the linked html
20839  * element, and moved to the exact location of the linked element.
20840  *
20841  * References to the "frame" element refer to the single proxy element that
20842  * was created to be dragged in place of all DDProxy elements on the
20843  * page.
20844  *
20845  * @extends Roo.dd.DD
20846  * @constructor
20847  * @param {String} id the id of the linked html element
20848  * @param {String} sGroup the group of related DragDrop objects
20849  * @param {object} config an object containing configurable attributes
20850  *                Valid properties for DDProxy in addition to those in DragDrop:
20851  *                   resizeFrame, centerFrame, dragElId
20852  */
20853 Roo.dd.DDProxy = function(id, sGroup, config) {
20854     if (id) {
20855         this.init(id, sGroup, config);
20856         this.initFrame();
20857     }
20858 };
20859
20860 /**
20861  * The default drag frame div id
20862  * @property Roo.dd.DDProxy.dragElId
20863  * @type String
20864  * @static
20865  */
20866 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20867
20868 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20869
20870     /**
20871      * By default we resize the drag frame to be the same size as the element
20872      * we want to drag (this is to get the frame effect).  We can turn it off
20873      * if we want a different behavior.
20874      * @property resizeFrame
20875      * @type boolean
20876      */
20877     resizeFrame: true,
20878
20879     /**
20880      * By default the frame is positioned exactly where the drag element is, so
20881      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20882      * you do not have constraints on the obj is to have the drag frame centered
20883      * around the cursor.  Set centerFrame to true for this effect.
20884      * @property centerFrame
20885      * @type boolean
20886      */
20887     centerFrame: false,
20888
20889     /**
20890      * Creates the proxy element if it does not yet exist
20891      * @method createFrame
20892      */
20893     createFrame: function() {
20894         var self = this;
20895         var body = document.body;
20896
20897         if (!body || !body.firstChild) {
20898             setTimeout( function() { self.createFrame(); }, 50 );
20899             return;
20900         }
20901
20902         var div = this.getDragEl();
20903
20904         if (!div) {
20905             div    = document.createElement("div");
20906             div.id = this.dragElId;
20907             var s  = div.style;
20908
20909             s.position   = "absolute";
20910             s.visibility = "hidden";
20911             s.cursor     = "move";
20912             s.border     = "2px solid #aaa";
20913             s.zIndex     = 999;
20914
20915             // appendChild can blow up IE if invoked prior to the window load event
20916             // while rendering a table.  It is possible there are other scenarios
20917             // that would cause this to happen as well.
20918             body.insertBefore(div, body.firstChild);
20919         }
20920     },
20921
20922     /**
20923      * Initialization for the drag frame element.  Must be called in the
20924      * constructor of all subclasses
20925      * @method initFrame
20926      */
20927     initFrame: function() {
20928         this.createFrame();
20929     },
20930
20931     applyConfig: function() {
20932         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20933
20934         this.resizeFrame = (this.config.resizeFrame !== false);
20935         this.centerFrame = (this.config.centerFrame);
20936         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20937     },
20938
20939     /**
20940      * Resizes the drag frame to the dimensions of the clicked object, positions
20941      * it over the object, and finally displays it
20942      * @method showFrame
20943      * @param {int} iPageX X click position
20944      * @param {int} iPageY Y click position
20945      * @private
20946      */
20947     showFrame: function(iPageX, iPageY) {
20948         var el = this.getEl();
20949         var dragEl = this.getDragEl();
20950         var s = dragEl.style;
20951
20952         this._resizeProxy();
20953
20954         if (this.centerFrame) {
20955             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20956                            Math.round(parseInt(s.height, 10)/2) );
20957         }
20958
20959         this.setDragElPos(iPageX, iPageY);
20960
20961         Roo.fly(dragEl).show();
20962     },
20963
20964     /**
20965      * The proxy is automatically resized to the dimensions of the linked
20966      * element when a drag is initiated, unless resizeFrame is set to false
20967      * @method _resizeProxy
20968      * @private
20969      */
20970     _resizeProxy: function() {
20971         if (this.resizeFrame) {
20972             var el = this.getEl();
20973             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20974         }
20975     },
20976
20977     // overrides Roo.dd.DragDrop
20978     b4MouseDown: function(e) {
20979         var x = e.getPageX();
20980         var y = e.getPageY();
20981         this.autoOffset(x, y);
20982         this.setDragElPos(x, y);
20983     },
20984
20985     // overrides Roo.dd.DragDrop
20986     b4StartDrag: function(x, y) {
20987         // show the drag frame
20988         this.showFrame(x, y);
20989     },
20990
20991     // overrides Roo.dd.DragDrop
20992     b4EndDrag: function(e) {
20993         Roo.fly(this.getDragEl()).hide();
20994     },
20995
20996     // overrides Roo.dd.DragDrop
20997     // By default we try to move the element to the last location of the frame.
20998     // This is so that the default behavior mirrors that of Roo.dd.DD.
20999     endDrag: function(e) {
21000
21001         var lel = this.getEl();
21002         var del = this.getDragEl();
21003
21004         // Show the drag frame briefly so we can get its position
21005         del.style.visibility = "";
21006
21007         this.beforeMove();
21008         // Hide the linked element before the move to get around a Safari
21009         // rendering bug.
21010         lel.style.visibility = "hidden";
21011         Roo.dd.DDM.moveToEl(lel, del);
21012         del.style.visibility = "hidden";
21013         lel.style.visibility = "";
21014
21015         this.afterDrag();
21016     },
21017
21018     beforeMove : function(){
21019
21020     },
21021
21022     afterDrag : function(){
21023
21024     },
21025
21026     toString: function() {
21027         return ("DDProxy " + this.id);
21028     }
21029
21030 });
21031 /*
21032  * Based on:
21033  * Ext JS Library 1.1.1
21034  * Copyright(c) 2006-2007, Ext JS, LLC.
21035  *
21036  * Originally Released Under LGPL - original licence link has changed is not relivant.
21037  *
21038  * Fork - LGPL
21039  * <script type="text/javascript">
21040  */
21041
21042  /**
21043  * @class Roo.dd.DDTarget
21044  * A DragDrop implementation that does not move, but can be a drop
21045  * target.  You would get the same result by simply omitting implementation
21046  * for the event callbacks, but this way we reduce the processing cost of the
21047  * event listener and the callbacks.
21048  * @extends Roo.dd.DragDrop
21049  * @constructor
21050  * @param {String} id the id of the element that is a drop target
21051  * @param {String} sGroup the group of related DragDrop objects
21052  * @param {object} config an object containing configurable attributes
21053  *                 Valid properties for DDTarget in addition to those in
21054  *                 DragDrop:
21055  *                    none
21056  */
21057 Roo.dd.DDTarget = function(id, sGroup, config) {
21058     if (id) {
21059         this.initTarget(id, sGroup, config);
21060     }
21061     if (config.listeners || config.events) { 
21062        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21063             listeners : config.listeners || {}, 
21064             events : config.events || {} 
21065         });    
21066     }
21067 };
21068
21069 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21070 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21071     toString: function() {
21072         return ("DDTarget " + this.id);
21073     }
21074 });
21075 /*
21076  * Based on:
21077  * Ext JS Library 1.1.1
21078  * Copyright(c) 2006-2007, Ext JS, LLC.
21079  *
21080  * Originally Released Under LGPL - original licence link has changed is not relivant.
21081  *
21082  * Fork - LGPL
21083  * <script type="text/javascript">
21084  */
21085  
21086
21087 /**
21088  * @class Roo.dd.ScrollManager
21089  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21090  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21091  * @singleton
21092  */
21093 Roo.dd.ScrollManager = function(){
21094     var ddm = Roo.dd.DragDropMgr;
21095     var els = {};
21096     var dragEl = null;
21097     var proc = {};
21098     
21099     
21100     
21101     var onStop = function(e){
21102         dragEl = null;
21103         clearProc();
21104     };
21105     
21106     var triggerRefresh = function(){
21107         if(ddm.dragCurrent){
21108              ddm.refreshCache(ddm.dragCurrent.groups);
21109         }
21110     };
21111     
21112     var doScroll = function(){
21113         if(ddm.dragCurrent){
21114             var dds = Roo.dd.ScrollManager;
21115             if(!dds.animate){
21116                 if(proc.el.scroll(proc.dir, dds.increment)){
21117                     triggerRefresh();
21118                 }
21119             }else{
21120                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21121             }
21122         }
21123     };
21124     
21125     var clearProc = function(){
21126         if(proc.id){
21127             clearInterval(proc.id);
21128         }
21129         proc.id = 0;
21130         proc.el = null;
21131         proc.dir = "";
21132     };
21133     
21134     var startProc = function(el, dir){
21135          Roo.log('scroll startproc');
21136         clearProc();
21137         proc.el = el;
21138         proc.dir = dir;
21139         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21140     };
21141     
21142     var onFire = function(e, isDrop){
21143        
21144         if(isDrop || !ddm.dragCurrent){ return; }
21145         var dds = Roo.dd.ScrollManager;
21146         if(!dragEl || dragEl != ddm.dragCurrent){
21147             dragEl = ddm.dragCurrent;
21148             // refresh regions on drag start
21149             dds.refreshCache();
21150         }
21151         
21152         var xy = Roo.lib.Event.getXY(e);
21153         var pt = new Roo.lib.Point(xy[0], xy[1]);
21154         for(var id in els){
21155             var el = els[id], r = el._region;
21156             if(r && r.contains(pt) && el.isScrollable()){
21157                 if(r.bottom - pt.y <= dds.thresh){
21158                     if(proc.el != el){
21159                         startProc(el, "down");
21160                     }
21161                     return;
21162                 }else if(r.right - pt.x <= dds.thresh){
21163                     if(proc.el != el){
21164                         startProc(el, "left");
21165                     }
21166                     return;
21167                 }else if(pt.y - r.top <= dds.thresh){
21168                     if(proc.el != el){
21169                         startProc(el, "up");
21170                     }
21171                     return;
21172                 }else if(pt.x - r.left <= dds.thresh){
21173                     if(proc.el != el){
21174                         startProc(el, "right");
21175                     }
21176                     return;
21177                 }
21178             }
21179         }
21180         clearProc();
21181     };
21182     
21183     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21184     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21185     
21186     return {
21187         /**
21188          * Registers new overflow element(s) to auto scroll
21189          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21190          */
21191         register : function(el){
21192             if(el instanceof Array){
21193                 for(var i = 0, len = el.length; i < len; i++) {
21194                         this.register(el[i]);
21195                 }
21196             }else{
21197                 el = Roo.get(el);
21198                 els[el.id] = el;
21199             }
21200             Roo.dd.ScrollManager.els = els;
21201         },
21202         
21203         /**
21204          * Unregisters overflow element(s) so they are no longer scrolled
21205          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21206          */
21207         unregister : function(el){
21208             if(el instanceof Array){
21209                 for(var i = 0, len = el.length; i < len; i++) {
21210                         this.unregister(el[i]);
21211                 }
21212             }else{
21213                 el = Roo.get(el);
21214                 delete els[el.id];
21215             }
21216         },
21217         
21218         /**
21219          * The number of pixels from the edge of a container the pointer needs to be to 
21220          * trigger scrolling (defaults to 25)
21221          * @type Number
21222          */
21223         thresh : 25,
21224         
21225         /**
21226          * The number of pixels to scroll in each scroll increment (defaults to 50)
21227          * @type Number
21228          */
21229         increment : 100,
21230         
21231         /**
21232          * The frequency of scrolls in milliseconds (defaults to 500)
21233          * @type Number
21234          */
21235         frequency : 500,
21236         
21237         /**
21238          * True to animate the scroll (defaults to true)
21239          * @type Boolean
21240          */
21241         animate: true,
21242         
21243         /**
21244          * The animation duration in seconds - 
21245          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21246          * @type Number
21247          */
21248         animDuration: .4,
21249         
21250         /**
21251          * Manually trigger a cache refresh.
21252          */
21253         refreshCache : function(){
21254             for(var id in els){
21255                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21256                     els[id]._region = els[id].getRegion();
21257                 }
21258             }
21259         }
21260     };
21261 }();/*
21262  * Based on:
21263  * Ext JS Library 1.1.1
21264  * Copyright(c) 2006-2007, Ext JS, LLC.
21265  *
21266  * Originally Released Under LGPL - original licence link has changed is not relivant.
21267  *
21268  * Fork - LGPL
21269  * <script type="text/javascript">
21270  */
21271  
21272
21273 /**
21274  * @class Roo.dd.Registry
21275  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21276  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21277  * @singleton
21278  */
21279 Roo.dd.Registry = function(){
21280     var elements = {}; 
21281     var handles = {}; 
21282     var autoIdSeed = 0;
21283
21284     var getId = function(el, autogen){
21285         if(typeof el == "string"){
21286             return el;
21287         }
21288         var id = el.id;
21289         if(!id && autogen !== false){
21290             id = "roodd-" + (++autoIdSeed);
21291             el.id = id;
21292         }
21293         return id;
21294     };
21295     
21296     return {
21297     /**
21298      * Register a drag drop element
21299      * @param {String|HTMLElement} element The id or DOM node to register
21300      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21301      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21302      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21303      * populated in the data object (if applicable):
21304      * <pre>
21305 Value      Description<br />
21306 ---------  ------------------------------------------<br />
21307 handles    Array of DOM nodes that trigger dragging<br />
21308            for the element being registered<br />
21309 isHandle   True if the element passed in triggers<br />
21310            dragging itself, else false
21311 </pre>
21312      */
21313         register : function(el, data){
21314             data = data || {};
21315             if(typeof el == "string"){
21316                 el = document.getElementById(el);
21317             }
21318             data.ddel = el;
21319             elements[getId(el)] = data;
21320             if(data.isHandle !== false){
21321                 handles[data.ddel.id] = data;
21322             }
21323             if(data.handles){
21324                 var hs = data.handles;
21325                 for(var i = 0, len = hs.length; i < len; i++){
21326                         handles[getId(hs[i])] = data;
21327                 }
21328             }
21329         },
21330
21331     /**
21332      * Unregister a drag drop element
21333      * @param {String|HTMLElement}  element The id or DOM node to unregister
21334      */
21335         unregister : function(el){
21336             var id = getId(el, false);
21337             var data = elements[id];
21338             if(data){
21339                 delete elements[id];
21340                 if(data.handles){
21341                     var hs = data.handles;
21342                     for(var i = 0, len = hs.length; i < len; i++){
21343                         delete handles[getId(hs[i], false)];
21344                     }
21345                 }
21346             }
21347         },
21348
21349     /**
21350      * Returns the handle registered for a DOM Node by id
21351      * @param {String|HTMLElement} id The DOM node or id to look up
21352      * @return {Object} handle The custom handle data
21353      */
21354         getHandle : function(id){
21355             if(typeof id != "string"){ // must be element?
21356                 id = id.id;
21357             }
21358             return handles[id];
21359         },
21360
21361     /**
21362      * Returns the handle that is registered for the DOM node that is the target of the event
21363      * @param {Event} e The event
21364      * @return {Object} handle The custom handle data
21365      */
21366         getHandleFromEvent : function(e){
21367             var t = Roo.lib.Event.getTarget(e);
21368             return t ? handles[t.id] : null;
21369         },
21370
21371     /**
21372      * Returns a custom data object that is registered for a DOM node by id
21373      * @param {String|HTMLElement} id The DOM node or id to look up
21374      * @return {Object} data The custom data
21375      */
21376         getTarget : function(id){
21377             if(typeof id != "string"){ // must be element?
21378                 id = id.id;
21379             }
21380             return elements[id];
21381         },
21382
21383     /**
21384      * Returns a custom data object that is registered for the DOM node that is the target of the event
21385      * @param {Event} e The event
21386      * @return {Object} data The custom data
21387      */
21388         getTargetFromEvent : function(e){
21389             var t = Roo.lib.Event.getTarget(e);
21390             return t ? elements[t.id] || handles[t.id] : null;
21391         }
21392     };
21393 }();/*
21394  * Based on:
21395  * Ext JS Library 1.1.1
21396  * Copyright(c) 2006-2007, Ext JS, LLC.
21397  *
21398  * Originally Released Under LGPL - original licence link has changed is not relivant.
21399  *
21400  * Fork - LGPL
21401  * <script type="text/javascript">
21402  */
21403  
21404
21405 /**
21406  * @class Roo.dd.StatusProxy
21407  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21408  * default drag proxy used by all Roo.dd components.
21409  * @constructor
21410  * @param {Object} config
21411  */
21412 Roo.dd.StatusProxy = function(config){
21413     Roo.apply(this, config);
21414     this.id = this.id || Roo.id();
21415     this.el = new Roo.Layer({
21416         dh: {
21417             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21418                 {tag: "div", cls: "x-dd-drop-icon"},
21419                 {tag: "div", cls: "x-dd-drag-ghost"}
21420             ]
21421         }, 
21422         shadow: !config || config.shadow !== false
21423     });
21424     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21425     this.dropStatus = this.dropNotAllowed;
21426 };
21427
21428 Roo.dd.StatusProxy.prototype = {
21429     /**
21430      * @cfg {String} dropAllowed
21431      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21432      */
21433     dropAllowed : "x-dd-drop-ok",
21434     /**
21435      * @cfg {String} dropNotAllowed
21436      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21437      */
21438     dropNotAllowed : "x-dd-drop-nodrop",
21439
21440     /**
21441      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21442      * over the current target element.
21443      * @param {String} cssClass The css class for the new drop status indicator image
21444      */
21445     setStatus : function(cssClass){
21446         cssClass = cssClass || this.dropNotAllowed;
21447         if(this.dropStatus != cssClass){
21448             this.el.replaceClass(this.dropStatus, cssClass);
21449             this.dropStatus = cssClass;
21450         }
21451     },
21452
21453     /**
21454      * Resets the status indicator to the default dropNotAllowed value
21455      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21456      */
21457     reset : function(clearGhost){
21458         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21459         this.dropStatus = this.dropNotAllowed;
21460         if(clearGhost){
21461             this.ghost.update("");
21462         }
21463     },
21464
21465     /**
21466      * Updates the contents of the ghost element
21467      * @param {String} html The html that will replace the current innerHTML of the ghost element
21468      */
21469     update : function(html){
21470         if(typeof html == "string"){
21471             this.ghost.update(html);
21472         }else{
21473             this.ghost.update("");
21474             html.style.margin = "0";
21475             this.ghost.dom.appendChild(html);
21476         }
21477         // ensure float = none set?? cant remember why though.
21478         var el = this.ghost.dom.firstChild;
21479                 if(el){
21480                         Roo.fly(el).setStyle('float', 'none');
21481                 }
21482     },
21483     
21484     /**
21485      * Returns the underlying proxy {@link Roo.Layer}
21486      * @return {Roo.Layer} el
21487     */
21488     getEl : function(){
21489         return this.el;
21490     },
21491
21492     /**
21493      * Returns the ghost element
21494      * @return {Roo.Element} el
21495      */
21496     getGhost : function(){
21497         return this.ghost;
21498     },
21499
21500     /**
21501      * Hides the proxy
21502      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21503      */
21504     hide : function(clear){
21505         this.el.hide();
21506         if(clear){
21507             this.reset(true);
21508         }
21509     },
21510
21511     /**
21512      * Stops the repair animation if it's currently running
21513      */
21514     stop : function(){
21515         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21516             this.anim.stop();
21517         }
21518     },
21519
21520     /**
21521      * Displays this proxy
21522      */
21523     show : function(){
21524         this.el.show();
21525     },
21526
21527     /**
21528      * Force the Layer to sync its shadow and shim positions to the element
21529      */
21530     sync : function(){
21531         this.el.sync();
21532     },
21533
21534     /**
21535      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21536      * invalid drop operation by the item being dragged.
21537      * @param {Array} xy The XY position of the element ([x, y])
21538      * @param {Function} callback The function to call after the repair is complete
21539      * @param {Object} scope The scope in which to execute the callback
21540      */
21541     repair : function(xy, callback, scope){
21542         this.callback = callback;
21543         this.scope = scope;
21544         if(xy && this.animRepair !== false){
21545             this.el.addClass("x-dd-drag-repair");
21546             this.el.hideUnders(true);
21547             this.anim = this.el.shift({
21548                 duration: this.repairDuration || .5,
21549                 easing: 'easeOut',
21550                 xy: xy,
21551                 stopFx: true,
21552                 callback: this.afterRepair,
21553                 scope: this
21554             });
21555         }else{
21556             this.afterRepair();
21557         }
21558     },
21559
21560     // private
21561     afterRepair : function(){
21562         this.hide(true);
21563         if(typeof this.callback == "function"){
21564             this.callback.call(this.scope || this);
21565         }
21566         this.callback = null;
21567         this.scope = null;
21568     }
21569 };/*
21570  * Based on:
21571  * Ext JS Library 1.1.1
21572  * Copyright(c) 2006-2007, Ext JS, LLC.
21573  *
21574  * Originally Released Under LGPL - original licence link has changed is not relivant.
21575  *
21576  * Fork - LGPL
21577  * <script type="text/javascript">
21578  */
21579
21580 /**
21581  * @class Roo.dd.DragSource
21582  * @extends Roo.dd.DDProxy
21583  * A simple class that provides the basic implementation needed to make any element draggable.
21584  * @constructor
21585  * @param {String/HTMLElement/Element} el The container element
21586  * @param {Object} config
21587  */
21588 Roo.dd.DragSource = function(el, config){
21589     this.el = Roo.get(el);
21590     this.dragData = {};
21591     
21592     Roo.apply(this, config);
21593     
21594     if(!this.proxy){
21595         this.proxy = new Roo.dd.StatusProxy();
21596     }
21597
21598     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21599           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21600     
21601     this.dragging = false;
21602 };
21603
21604 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21605     /**
21606      * @cfg {String} dropAllowed
21607      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21608      */
21609     dropAllowed : "x-dd-drop-ok",
21610     /**
21611      * @cfg {String} dropNotAllowed
21612      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21613      */
21614     dropNotAllowed : "x-dd-drop-nodrop",
21615
21616     /**
21617      * Returns the data object associated with this drag source
21618      * @return {Object} data An object containing arbitrary data
21619      */
21620     getDragData : function(e){
21621         return this.dragData;
21622     },
21623
21624     // private
21625     onDragEnter : function(e, id){
21626         var target = Roo.dd.DragDropMgr.getDDById(id);
21627         this.cachedTarget = target;
21628         if(this.beforeDragEnter(target, e, id) !== false){
21629             if(target.isNotifyTarget){
21630                 var status = target.notifyEnter(this, e, this.dragData);
21631                 this.proxy.setStatus(status);
21632             }else{
21633                 this.proxy.setStatus(this.dropAllowed);
21634             }
21635             
21636             if(this.afterDragEnter){
21637                 /**
21638                  * An empty function by default, but provided so that you can perform a custom action
21639                  * when the dragged item enters the drop target by providing an implementation.
21640                  * @param {Roo.dd.DragDrop} target The drop target
21641                  * @param {Event} e The event object
21642                  * @param {String} id The id of the dragged element
21643                  * @method afterDragEnter
21644                  */
21645                 this.afterDragEnter(target, e, id);
21646             }
21647         }
21648     },
21649
21650     /**
21651      * An empty function by default, but provided so that you can perform a custom action
21652      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21653      * @param {Roo.dd.DragDrop} target The drop target
21654      * @param {Event} e The event object
21655      * @param {String} id The id of the dragged element
21656      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21657      */
21658     beforeDragEnter : function(target, e, id){
21659         return true;
21660     },
21661
21662     // private
21663     alignElWithMouse: function() {
21664         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21665         this.proxy.sync();
21666     },
21667
21668     // private
21669     onDragOver : function(e, id){
21670         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21671         if(this.beforeDragOver(target, e, id) !== false){
21672             if(target.isNotifyTarget){
21673                 var status = target.notifyOver(this, e, this.dragData);
21674                 this.proxy.setStatus(status);
21675             }
21676
21677             if(this.afterDragOver){
21678                 /**
21679                  * An empty function by default, but provided so that you can perform a custom action
21680                  * while the dragged item is over the drop target by providing an implementation.
21681                  * @param {Roo.dd.DragDrop} target The drop target
21682                  * @param {Event} e The event object
21683                  * @param {String} id The id of the dragged element
21684                  * @method afterDragOver
21685                  */
21686                 this.afterDragOver(target, e, id);
21687             }
21688         }
21689     },
21690
21691     /**
21692      * An empty function by default, but provided so that you can perform a custom action
21693      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21694      * @param {Roo.dd.DragDrop} target The drop target
21695      * @param {Event} e The event object
21696      * @param {String} id The id of the dragged element
21697      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21698      */
21699     beforeDragOver : function(target, e, id){
21700         return true;
21701     },
21702
21703     // private
21704     onDragOut : function(e, id){
21705         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21706         if(this.beforeDragOut(target, e, id) !== false){
21707             if(target.isNotifyTarget){
21708                 target.notifyOut(this, e, this.dragData);
21709             }
21710             this.proxy.reset();
21711             if(this.afterDragOut){
21712                 /**
21713                  * An empty function by default, but provided so that you can perform a custom action
21714                  * after the dragged item is dragged out of the target without dropping.
21715                  * @param {Roo.dd.DragDrop} target The drop target
21716                  * @param {Event} e The event object
21717                  * @param {String} id The id of the dragged element
21718                  * @method afterDragOut
21719                  */
21720                 this.afterDragOut(target, e, id);
21721             }
21722         }
21723         this.cachedTarget = null;
21724     },
21725
21726     /**
21727      * An empty function by default, but provided so that you can perform a custom action before the dragged
21728      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21729      * @param {Roo.dd.DragDrop} target The drop target
21730      * @param {Event} e The event object
21731      * @param {String} id The id of the dragged element
21732      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21733      */
21734     beforeDragOut : function(target, e, id){
21735         return true;
21736     },
21737     
21738     // private
21739     onDragDrop : function(e, id){
21740         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21741         if(this.beforeDragDrop(target, e, id) !== false){
21742             if(target.isNotifyTarget){
21743                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21744                     this.onValidDrop(target, e, id);
21745                 }else{
21746                     this.onInvalidDrop(target, e, id);
21747                 }
21748             }else{
21749                 this.onValidDrop(target, e, id);
21750             }
21751             
21752             if(this.afterDragDrop){
21753                 /**
21754                  * An empty function by default, but provided so that you can perform a custom action
21755                  * after a valid drag drop has occurred by providing an implementation.
21756                  * @param {Roo.dd.DragDrop} target The drop target
21757                  * @param {Event} e The event object
21758                  * @param {String} id The id of the dropped element
21759                  * @method afterDragDrop
21760                  */
21761                 this.afterDragDrop(target, e, id);
21762             }
21763         }
21764         delete this.cachedTarget;
21765     },
21766
21767     /**
21768      * An empty function by default, but provided so that you can perform a custom action before the dragged
21769      * item is dropped onto the target and optionally cancel the onDragDrop.
21770      * @param {Roo.dd.DragDrop} target The drop target
21771      * @param {Event} e The event object
21772      * @param {String} id The id of the dragged element
21773      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21774      */
21775     beforeDragDrop : function(target, e, id){
21776         return true;
21777     },
21778
21779     // private
21780     onValidDrop : function(target, e, id){
21781         this.hideProxy();
21782         if(this.afterValidDrop){
21783             /**
21784              * An empty function by default, but provided so that you can perform a custom action
21785              * after a valid drop has occurred by providing an implementation.
21786              * @param {Object} target The target DD 
21787              * @param {Event} e The event object
21788              * @param {String} id The id of the dropped element
21789              * @method afterInvalidDrop
21790              */
21791             this.afterValidDrop(target, e, id);
21792         }
21793     },
21794
21795     // private
21796     getRepairXY : function(e, data){
21797         return this.el.getXY();  
21798     },
21799
21800     // private
21801     onInvalidDrop : function(target, e, id){
21802         this.beforeInvalidDrop(target, e, id);
21803         if(this.cachedTarget){
21804             if(this.cachedTarget.isNotifyTarget){
21805                 this.cachedTarget.notifyOut(this, e, this.dragData);
21806             }
21807             this.cacheTarget = null;
21808         }
21809         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21810
21811         if(this.afterInvalidDrop){
21812             /**
21813              * An empty function by default, but provided so that you can perform a custom action
21814              * after an invalid drop has occurred by providing an implementation.
21815              * @param {Event} e The event object
21816              * @param {String} id The id of the dropped element
21817              * @method afterInvalidDrop
21818              */
21819             this.afterInvalidDrop(e, id);
21820         }
21821     },
21822
21823     // private
21824     afterRepair : function(){
21825         if(Roo.enableFx){
21826             this.el.highlight(this.hlColor || "c3daf9");
21827         }
21828         this.dragging = false;
21829     },
21830
21831     /**
21832      * An empty function by default, but provided so that you can perform a custom action after an invalid
21833      * drop has occurred.
21834      * @param {Roo.dd.DragDrop} target The drop target
21835      * @param {Event} e The event object
21836      * @param {String} id The id of the dragged element
21837      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21838      */
21839     beforeInvalidDrop : function(target, e, id){
21840         return true;
21841     },
21842
21843     // private
21844     handleMouseDown : function(e){
21845         if(this.dragging) {
21846             return;
21847         }
21848         var data = this.getDragData(e);
21849         if(data && this.onBeforeDrag(data, e) !== false){
21850             this.dragData = data;
21851             this.proxy.stop();
21852             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21853         } 
21854     },
21855
21856     /**
21857      * An empty function by default, but provided so that you can perform a custom action before the initial
21858      * drag event begins and optionally cancel it.
21859      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21860      * @param {Event} e The event object
21861      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21862      */
21863     onBeforeDrag : function(data, e){
21864         return true;
21865     },
21866
21867     /**
21868      * An empty function by default, but provided so that you can perform a custom action once the initial
21869      * drag event has begun.  The drag cannot be canceled from this function.
21870      * @param {Number} x The x position of the click on the dragged object
21871      * @param {Number} y The y position of the click on the dragged object
21872      */
21873     onStartDrag : Roo.emptyFn,
21874
21875     // private - YUI override
21876     startDrag : function(x, y){
21877         this.proxy.reset();
21878         this.dragging = true;
21879         this.proxy.update("");
21880         this.onInitDrag(x, y);
21881         this.proxy.show();
21882     },
21883
21884     // private
21885     onInitDrag : function(x, y){
21886         var clone = this.el.dom.cloneNode(true);
21887         clone.id = Roo.id(); // prevent duplicate ids
21888         this.proxy.update(clone);
21889         this.onStartDrag(x, y);
21890         return true;
21891     },
21892
21893     /**
21894      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21895      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21896      */
21897     getProxy : function(){
21898         return this.proxy;  
21899     },
21900
21901     /**
21902      * Hides the drag source's {@link Roo.dd.StatusProxy}
21903      */
21904     hideProxy : function(){
21905         this.proxy.hide();  
21906         this.proxy.reset(true);
21907         this.dragging = false;
21908     },
21909
21910     // private
21911     triggerCacheRefresh : function(){
21912         Roo.dd.DDM.refreshCache(this.groups);
21913     },
21914
21915     // private - override to prevent hiding
21916     b4EndDrag: function(e) {
21917     },
21918
21919     // private - override to prevent moving
21920     endDrag : function(e){
21921         this.onEndDrag(this.dragData, e);
21922     },
21923
21924     // private
21925     onEndDrag : function(data, e){
21926     },
21927     
21928     // private - pin to cursor
21929     autoOffset : function(x, y) {
21930         this.setDelta(-12, -20);
21931     }    
21932 });/*
21933  * Based on:
21934  * Ext JS Library 1.1.1
21935  * Copyright(c) 2006-2007, Ext JS, LLC.
21936  *
21937  * Originally Released Under LGPL - original licence link has changed is not relivant.
21938  *
21939  * Fork - LGPL
21940  * <script type="text/javascript">
21941  */
21942
21943
21944 /**
21945  * @class Roo.dd.DropTarget
21946  * @extends Roo.dd.DDTarget
21947  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21948  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21949  * @constructor
21950  * @param {String/HTMLElement/Element} el The container element
21951  * @param {Object} config
21952  */
21953 Roo.dd.DropTarget = function(el, config){
21954     this.el = Roo.get(el);
21955     
21956     var listeners = false; ;
21957     if (config && config.listeners) {
21958         listeners= config.listeners;
21959         delete config.listeners;
21960     }
21961     Roo.apply(this, config);
21962     
21963     if(this.containerScroll){
21964         Roo.dd.ScrollManager.register(this.el);
21965     }
21966     this.addEvents( {
21967          /**
21968          * @scope Roo.dd.DropTarget
21969          */
21970          
21971          /**
21972          * @event enter
21973          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21974          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21975          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21976          * 
21977          * IMPORTANT : it should set this.overClass and this.dropAllowed
21978          * 
21979          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21980          * @param {Event} e The event
21981          * @param {Object} data An object containing arbitrary data supplied by the drag source
21982          */
21983         "enter" : true,
21984         
21985          /**
21986          * @event over
21987          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21988          * This method will be called on every mouse movement while the drag source is over the drop target.
21989          * This default implementation simply returns the dropAllowed config value.
21990          * 
21991          * IMPORTANT : it should set this.dropAllowed
21992          * 
21993          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21994          * @param {Event} e The event
21995          * @param {Object} data An object containing arbitrary data supplied by the drag source
21996          
21997          */
21998         "over" : true,
21999         /**
22000          * @event out
22001          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22002          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
22003          * overClass (if any) from the drop element.
22004          * 
22005          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22006          * @param {Event} e The event
22007          * @param {Object} data An object containing arbitrary data supplied by the drag source
22008          */
22009          "out" : true,
22010          
22011         /**
22012          * @event drop
22013          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22014          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
22015          * implementation that does something to process the drop event and returns true so that the drag source's
22016          * repair action does not run.
22017          * 
22018          * IMPORTANT : it should set this.success
22019          * 
22020          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22021          * @param {Event} e The event
22022          * @param {Object} data An object containing arbitrary data supplied by the drag source
22023         */
22024          "drop" : true
22025     });
22026             
22027      
22028     Roo.dd.DropTarget.superclass.constructor.call(  this, 
22029         this.el.dom, 
22030         this.ddGroup || this.group,
22031         {
22032             isTarget: true,
22033             listeners : listeners || {} 
22034            
22035         
22036         }
22037     );
22038
22039 };
22040
22041 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22042     /**
22043      * @cfg {String} overClass
22044      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22045      */
22046      /**
22047      * @cfg {String} ddGroup
22048      * The drag drop group to handle drop events for
22049      */
22050      
22051     /**
22052      * @cfg {String} dropAllowed
22053      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22054      */
22055     dropAllowed : "x-dd-drop-ok",
22056     /**
22057      * @cfg {String} dropNotAllowed
22058      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22059      */
22060     dropNotAllowed : "x-dd-drop-nodrop",
22061     /**
22062      * @cfg {boolean} success
22063      * set this after drop listener.. 
22064      */
22065     success : false,
22066     /**
22067      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22068      * if the drop point is valid for over/enter..
22069      */
22070     valid : false,
22071     // private
22072     isTarget : true,
22073
22074     // private
22075     isNotifyTarget : true,
22076     
22077     /**
22078      * @hide
22079      */
22080     notifyEnter : function(dd, e, data)
22081     {
22082         this.valid = true;
22083         this.fireEvent('enter', dd, e, data);
22084         if(this.overClass){
22085             this.el.addClass(this.overClass);
22086         }
22087         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22088             this.valid ? this.dropAllowed : this.dropNotAllowed
22089         );
22090     },
22091
22092     /**
22093      * @hide
22094      */
22095     notifyOver : function(dd, e, data)
22096     {
22097         this.valid = true;
22098         this.fireEvent('over', dd, e, data);
22099         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22100             this.valid ? this.dropAllowed : this.dropNotAllowed
22101         );
22102     },
22103
22104     /**
22105      * @hide
22106      */
22107     notifyOut : function(dd, e, data)
22108     {
22109         this.fireEvent('out', dd, e, data);
22110         if(this.overClass){
22111             this.el.removeClass(this.overClass);
22112         }
22113     },
22114
22115     /**
22116      * @hide
22117      */
22118     notifyDrop : function(dd, e, data)
22119     {
22120         this.success = false;
22121         this.fireEvent('drop', dd, e, data);
22122         return this.success;
22123     }
22124 });/*
22125  * Based on:
22126  * Ext JS Library 1.1.1
22127  * Copyright(c) 2006-2007, Ext JS, LLC.
22128  *
22129  * Originally Released Under LGPL - original licence link has changed is not relivant.
22130  *
22131  * Fork - LGPL
22132  * <script type="text/javascript">
22133  */
22134
22135
22136 /**
22137  * @class Roo.dd.DragZone
22138  * @extends Roo.dd.DragSource
22139  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22140  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22141  * @constructor
22142  * @param {String/HTMLElement/Element} el The container element
22143  * @param {Object} config
22144  */
22145 Roo.dd.DragZone = function(el, config){
22146     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22147     if(this.containerScroll){
22148         Roo.dd.ScrollManager.register(this.el);
22149     }
22150 };
22151
22152 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22153     /**
22154      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22155      * for auto scrolling during drag operations.
22156      */
22157     /**
22158      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22159      * method after a failed drop (defaults to "c3daf9" - light blue)
22160      */
22161
22162     /**
22163      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22164      * for a valid target to drag based on the mouse down. Override this method
22165      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22166      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22167      * @param {EventObject} e The mouse down event
22168      * @return {Object} The dragData
22169      */
22170     getDragData : function(e){
22171         return Roo.dd.Registry.getHandleFromEvent(e);
22172     },
22173     
22174     /**
22175      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22176      * this.dragData.ddel
22177      * @param {Number} x The x position of the click on the dragged object
22178      * @param {Number} y The y position of the click on the dragged object
22179      * @return {Boolean} true to continue the drag, false to cancel
22180      */
22181     onInitDrag : function(x, y){
22182         this.proxy.update(this.dragData.ddel.cloneNode(true));
22183         this.onStartDrag(x, y);
22184         return true;
22185     },
22186     
22187     /**
22188      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22189      */
22190     afterRepair : function(){
22191         if(Roo.enableFx){
22192             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22193         }
22194         this.dragging = false;
22195     },
22196
22197     /**
22198      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22199      * the XY of this.dragData.ddel
22200      * @param {EventObject} e The mouse up event
22201      * @return {Array} The xy location (e.g. [100, 200])
22202      */
22203     getRepairXY : function(e){
22204         return Roo.Element.fly(this.dragData.ddel).getXY();  
22205     }
22206 });/*
22207  * Based on:
22208  * Ext JS Library 1.1.1
22209  * Copyright(c) 2006-2007, Ext JS, LLC.
22210  *
22211  * Originally Released Under LGPL - original licence link has changed is not relivant.
22212  *
22213  * Fork - LGPL
22214  * <script type="text/javascript">
22215  */
22216 /**
22217  * @class Roo.dd.DropZone
22218  * @extends Roo.dd.DropTarget
22219  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22220  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22221  * @constructor
22222  * @param {String/HTMLElement/Element} el The container element
22223  * @param {Object} config
22224  */
22225 Roo.dd.DropZone = function(el, config){
22226     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22227 };
22228
22229 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22230     /**
22231      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22232      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22233      * provide your own custom lookup.
22234      * @param {Event} e The event
22235      * @return {Object} data The custom data
22236      */
22237     getTargetFromEvent : function(e){
22238         return Roo.dd.Registry.getTargetFromEvent(e);
22239     },
22240
22241     /**
22242      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22243      * that it has registered.  This method has no default implementation and should be overridden to provide
22244      * node-specific processing if necessary.
22245      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22246      * {@link #getTargetFromEvent} for this node)
22247      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22248      * @param {Event} e The event
22249      * @param {Object} data An object containing arbitrary data supplied by the drag source
22250      */
22251     onNodeEnter : function(n, dd, e, data){
22252         
22253     },
22254
22255     /**
22256      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22257      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22258      * overridden to provide the proper feedback.
22259      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22260      * {@link #getTargetFromEvent} for this node)
22261      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22262      * @param {Event} e The event
22263      * @param {Object} data An object containing arbitrary data supplied by the drag source
22264      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22265      * underlying {@link Roo.dd.StatusProxy} can be updated
22266      */
22267     onNodeOver : function(n, dd, e, data){
22268         return this.dropAllowed;
22269     },
22270
22271     /**
22272      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22273      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22274      * node-specific processing if necessary.
22275      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22276      * {@link #getTargetFromEvent} for this node)
22277      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22278      * @param {Event} e The event
22279      * @param {Object} data An object containing arbitrary data supplied by the drag source
22280      */
22281     onNodeOut : function(n, dd, e, data){
22282         
22283     },
22284
22285     /**
22286      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22287      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22288      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22289      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22290      * {@link #getTargetFromEvent} for this node)
22291      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22292      * @param {Event} e The event
22293      * @param {Object} data An object containing arbitrary data supplied by the drag source
22294      * @return {Boolean} True if the drop was valid, else false
22295      */
22296     onNodeDrop : function(n, dd, e, data){
22297         return false;
22298     },
22299
22300     /**
22301      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22302      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22303      * it should be overridden to provide the proper feedback if necessary.
22304      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22305      * @param {Event} e The event
22306      * @param {Object} data An object containing arbitrary data supplied by the drag source
22307      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22308      * underlying {@link Roo.dd.StatusProxy} can be updated
22309      */
22310     onContainerOver : function(dd, e, data){
22311         return this.dropNotAllowed;
22312     },
22313
22314     /**
22315      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22316      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22317      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22318      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22319      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22320      * @param {Event} e The event
22321      * @param {Object} data An object containing arbitrary data supplied by the drag source
22322      * @return {Boolean} True if the drop was valid, else false
22323      */
22324     onContainerDrop : function(dd, e, data){
22325         return false;
22326     },
22327
22328     /**
22329      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22330      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22331      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22332      * you should override this method and provide a custom implementation.
22333      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22334      * @param {Event} e The event
22335      * @param {Object} data An object containing arbitrary data supplied by the drag source
22336      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22337      * underlying {@link Roo.dd.StatusProxy} can be updated
22338      */
22339     notifyEnter : function(dd, e, data){
22340         return this.dropNotAllowed;
22341     },
22342
22343     /**
22344      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22345      * This method will be called on every mouse movement while the drag source is over the drop zone.
22346      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22347      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22348      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22349      * registered node, it will call {@link #onContainerOver}.
22350      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22351      * @param {Event} e The event
22352      * @param {Object} data An object containing arbitrary data supplied by the drag source
22353      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22354      * underlying {@link Roo.dd.StatusProxy} can be updated
22355      */
22356     notifyOver : function(dd, e, data){
22357         var n = this.getTargetFromEvent(e);
22358         if(!n){ // not over valid drop target
22359             if(this.lastOverNode){
22360                 this.onNodeOut(this.lastOverNode, dd, e, data);
22361                 this.lastOverNode = null;
22362             }
22363             return this.onContainerOver(dd, e, data);
22364         }
22365         if(this.lastOverNode != n){
22366             if(this.lastOverNode){
22367                 this.onNodeOut(this.lastOverNode, dd, e, data);
22368             }
22369             this.onNodeEnter(n, dd, e, data);
22370             this.lastOverNode = n;
22371         }
22372         return this.onNodeOver(n, dd, e, data);
22373     },
22374
22375     /**
22376      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22377      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22378      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22379      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22380      * @param {Event} e The event
22381      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22382      */
22383     notifyOut : function(dd, e, data){
22384         if(this.lastOverNode){
22385             this.onNodeOut(this.lastOverNode, dd, e, data);
22386             this.lastOverNode = null;
22387         }
22388     },
22389
22390     /**
22391      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22392      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22393      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22394      * otherwise it will call {@link #onContainerDrop}.
22395      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22396      * @param {Event} e The event
22397      * @param {Object} data An object containing arbitrary data supplied by the drag source
22398      * @return {Boolean} True if the drop was valid, else false
22399      */
22400     notifyDrop : function(dd, e, data){
22401         if(this.lastOverNode){
22402             this.onNodeOut(this.lastOverNode, dd, e, data);
22403             this.lastOverNode = null;
22404         }
22405         var n = this.getTargetFromEvent(e);
22406         return n ?
22407             this.onNodeDrop(n, dd, e, data) :
22408             this.onContainerDrop(dd, e, data);
22409     },
22410
22411     // private
22412     triggerCacheRefresh : function(){
22413         Roo.dd.DDM.refreshCache(this.groups);
22414     }  
22415 });