roojs-ui.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  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957
958 /**
959   * Make the first letter of a string uppercase
960   *
961   * @return {String} The new string.
962   */
963 String.prototype.toUpperCaseFirst = function () {
964     return this.charAt(0).toUpperCase() + this.slice(1);
965 };  
966   
967 /*
968  * Based on:
969  * Ext JS Library 1.1.1
970  * Copyright(c) 2006-2007, Ext JS, LLC.
971  *
972  * Originally Released Under LGPL - original licence link has changed is not relivant.
973  *
974  * Fork - LGPL
975  * <script type="text/javascript">
976  */
977
978  /**
979  * @class Number
980  */
981 Roo.applyIf(Number.prototype, {
982     /**
983      * Checks whether or not the current number is within a desired range.  If the number is already within the
984      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985      * exceeded.  Note that this method returns the constrained value but does not change the current number.
986      * @param {Number} min The minimum number in the range
987      * @param {Number} max The maximum number in the range
988      * @return {Number} The constrained value if outside the range, otherwise the current value
989      */
990     constrain : function(min, max){
991         return Math.min(Math.max(this, min), max);
992     }
993 });/*
994  * Based on:
995  * Ext JS Library 1.1.1
996  * Copyright(c) 2006-2007, Ext JS, LLC.
997  *
998  * Originally Released Under LGPL - original licence link has changed is not relivant.
999  *
1000  * Fork - LGPL
1001  * <script type="text/javascript">
1002  */
1003  /**
1004  * @class Array
1005  */
1006 Roo.applyIf(Array.prototype, {
1007     /**
1008      * 
1009      * Checks whether or not the specified object exists in the array.
1010      * @param {Object} o The object to check for
1011      * @return {Number} The index of o in the array (or -1 if it is not found)
1012      */
1013     indexOf : function(o){
1014        for (var i = 0, len = this.length; i < len; i++){
1015               if(this[i] == o) { return i; }
1016        }
1017            return -1;
1018     },
1019
1020     /**
1021      * Removes the specified object from the array.  If the object is not found nothing happens.
1022      * @param {Object} o The object to remove
1023      */
1024     remove : function(o){
1025        var index = this.indexOf(o);
1026        if(index != -1){
1027            this.splice(index, 1);
1028        }
1029     },
1030     /**
1031      * Map (JS 1.6 compatibility)
1032      * @param {Function} function  to call
1033      */
1034     map : function(fun )
1035     {
1036         var len = this.length >>> 0;
1037         if (typeof fun != "function") {
1038             throw new TypeError();
1039         }
1040         var res = new Array(len);
1041         var thisp = arguments[1];
1042         for (var i = 0; i < len; i++)
1043         {
1044             if (i in this) {
1045                 res[i] = fun.call(thisp, this[i], i, this);
1046             }
1047         }
1048
1049         return res;
1050     },
1051     /**
1052      * equals
1053      * @param {Array} o The array to compare to
1054      * @returns {Boolean} true if the same
1055      */
1056     equals : function(b)
1057     {
1058             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1059         if (this === b) {
1060             return true;
1061         }
1062         if (b == null) {
1063             return false;
1064         }
1065         if (this.length !== b.length) {
1066             return false;
1067         }
1068           
1069         // sort?? a.sort().equals(b.sort());
1070           
1071         for (var i = 0; i < this.length; ++i) {
1072             if (this[i] !== b[i]) {
1073             return false;
1074             }
1075         }
1076         return true;
1077     } 
1078     
1079     
1080     
1081     
1082 });
1083
1084 Roo.applyIf(Array, {
1085  /**
1086      * from
1087      * @static
1088      * @param {Array} o Or Array like object (eg. nodelist)
1089      * @returns {Array} 
1090      */
1091     from : function(o)
1092     {
1093         var ret= [];
1094     
1095         for (var i =0; i < o.length; i++) { 
1096             ret[i] = o[i];
1097         }
1098         return ret;
1099       
1100     }
1101 });
1102 /*
1103  * Based on:
1104  * Ext JS Library 1.1.1
1105  * Copyright(c) 2006-2007, Ext JS, LLC.
1106  *
1107  * Originally Released Under LGPL - original licence link has changed is not relivant.
1108  *
1109  * Fork - LGPL
1110  * <script type="text/javascript">
1111  */
1112
1113 /**
1114  * @class Date
1115  *
1116  * The date parsing and format syntax is a subset of
1117  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118  * supported will provide results equivalent to their PHP versions.
1119  *
1120  * Following is the list of all currently supported formats:
1121  *<pre>
1122 Sample date:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1124
1125 Format  Output      Description
1126 ------  ----------  --------------------------------------------------------------
1127   d      10         Day of the month, 2 digits with leading zeros
1128   D      Wed        A textual representation of a day, three letters
1129   j      10         Day of the month without leading zeros
1130   l      Wednesday  A full textual representation of the day of the week
1131   S      th         English ordinal day of month suffix, 2 chars (use with j)
1132   w      3          Numeric representation of the day of the week
1133   z      9          The julian date, or day of the year (0-365)
1134   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135   F      January    A full textual representation of the month
1136   m      01         Numeric representation of a month, with leading zeros
1137   M      Jan        Month name abbreviation, three letters
1138   n      1          Numeric representation of a month, without leading zeros
1139   t      31         Number of days in the given month
1140   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1141   Y      2007       A full numeric representation of a year, 4 digits
1142   y      07         A two digit representation of a year
1143   a      pm         Lowercase Ante meridiem and Post meridiem
1144   A      PM         Uppercase Ante meridiem and Post meridiem
1145   g      3          12-hour format of an hour without leading zeros
1146   G      15         24-hour format of an hour without leading zeros
1147   h      03         12-hour format of an hour with leading zeros
1148   H      15         24-hour format of an hour with leading zeros
1149   i      05         Minutes with leading zeros
1150   s      01         Seconds, with leading zeros
1151   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1153   T      CST        Timezone setting of the machine running the code
1154   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1155 </pre>
1156  *
1157  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1158  * <pre><code>
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d'));                         //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1162 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
1163  </code></pre>
1164  *
1165  * Here are some standard date/time patterns that you might find helpful.  They
1166  * are not part of the source of Date.js, but to use them you can simply copy this
1167  * block of code into any script that is included after Date.js and they will also become
1168  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1169  * <pre><code>
1170 Date.patterns = {
1171     ISO8601Long:"Y-m-d H:i:s",
1172     ISO8601Short:"Y-m-d",
1173     ShortDate: "n/j/Y",
1174     LongDate: "l, F d, Y",
1175     FullDateTime: "l, F d, Y g:i:s A",
1176     MonthDay: "F d",
1177     ShortTime: "g:i A",
1178     LongTime: "g:i:s A",
1179     SortableDateTime: "Y-m-d\\TH:i:s",
1180     UniversalSortableDateTime: "Y-m-d H:i:sO",
1181     YearMonth: "F, Y"
1182 };
1183 </code></pre>
1184  *
1185  * Example usage:
1186  * <pre><code>
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1189  </code></pre>
1190  */
1191
1192 /*
1193  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194  * They generate precompiled functions from date formats instead of parsing and
1195  * processing the pattern every time you format a date.  These functions are available
1196  * on every Date object (any javascript function).
1197  *
1198  * The original article and download are here:
1199  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1200  *
1201  */
1202  
1203  
1204  // was in core
1205 /**
1206  Returns the number of milliseconds between this date and date
1207  @param {Date} date (optional) Defaults to now
1208  @return {Number} The diff in milliseconds
1209  @member Date getElapsed
1210  */
1211 Date.prototype.getElapsed = function(date) {
1212         return Math.abs((date || new Date()).getTime()-this.getTime());
1213 };
1214 // was in date file..
1215
1216
1217 // private
1218 Date.parseFunctions = {count:0};
1219 // private
1220 Date.parseRegexes = [];
1221 // private
1222 Date.formatFunctions = {count:0};
1223
1224 // private
1225 Date.prototype.dateFormat = function(format) {
1226     if (Date.formatFunctions[format] == null) {
1227         Date.createNewFormat(format);
1228     }
1229     var func = Date.formatFunctions[format];
1230     return this[func]();
1231 };
1232
1233
1234 /**
1235  * Formats a date given the supplied format string
1236  * @param {String} format The format string
1237  * @return {String} The formatted date
1238  * @method
1239  */
1240 Date.prototype.format = Date.prototype.dateFormat;
1241
1242 // private
1243 Date.createNewFormat = function(format) {
1244     var funcName = "format" + Date.formatFunctions.count++;
1245     Date.formatFunctions[format] = funcName;
1246     var code = "Date.prototype." + funcName + " = function(){return ";
1247     var special = false;
1248     var ch = '';
1249     for (var i = 0; i < format.length; ++i) {
1250         ch = format.charAt(i);
1251         if (!special && ch == "\\") {
1252             special = true;
1253         }
1254         else if (special) {
1255             special = false;
1256             code += "'" + String.escape(ch) + "' + ";
1257         }
1258         else {
1259             code += Date.getFormatCode(ch);
1260         }
1261     }
1262     /** eval:var:zzzzzzzzzzzzz */
1263     eval(code.substring(0, code.length - 3) + ";}");
1264 };
1265
1266 // private
1267 Date.getFormatCode = function(character) {
1268     switch (character) {
1269     case "d":
1270         return "String.leftPad(this.getDate(), 2, '0') + ";
1271     case "D":
1272         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1273     case "j":
1274         return "this.getDate() + ";
1275     case "l":
1276         return "Date.dayNames[this.getDay()] + ";
1277     case "S":
1278         return "this.getSuffix() + ";
1279     case "w":
1280         return "this.getDay() + ";
1281     case "z":
1282         return "this.getDayOfYear() + ";
1283     case "W":
1284         return "this.getWeekOfYear() + ";
1285     case "F":
1286         return "Date.monthNames[this.getMonth()] + ";
1287     case "m":
1288         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1289     case "M":
1290         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1291     case "n":
1292         return "(this.getMonth() + 1) + ";
1293     case "t":
1294         return "this.getDaysInMonth() + ";
1295     case "L":
1296         return "(this.isLeapYear() ? 1 : 0) + ";
1297     case "Y":
1298         return "this.getFullYear() + ";
1299     case "y":
1300         return "('' + this.getFullYear()).substring(2, 4) + ";
1301     case "a":
1302         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1303     case "A":
1304         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1305     case "g":
1306         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1307     case "G":
1308         return "this.getHours() + ";
1309     case "h":
1310         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1311     case "H":
1312         return "String.leftPad(this.getHours(), 2, '0') + ";
1313     case "i":
1314         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1315     case "s":
1316         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1317     case "O":
1318         return "this.getGMTOffset() + ";
1319     case "P":
1320         return "this.getGMTColonOffset() + ";
1321     case "T":
1322         return "this.getTimezone() + ";
1323     case "Z":
1324         return "(this.getTimezoneOffset() * -60) + ";
1325     default:
1326         return "'" + String.escape(character) + "' + ";
1327     }
1328 };
1329
1330 /**
1331  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1332  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1333  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1334  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1335  * string or the parse operation will fail.
1336  * Example Usage:
1337 <pre><code>
1338 //dt = Fri May 25 2007 (current date)
1339 var dt = new Date();
1340
1341 //dt = Thu May 25 2006 (today's month/day in 2006)
1342 dt = Date.parseDate("2006", "Y");
1343
1344 //dt = Sun Jan 15 2006 (all date parts specified)
1345 dt = Date.parseDate("2006-1-15", "Y-m-d");
1346
1347 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1348 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1349 </code></pre>
1350  * @param {String} input The unparsed date as a string
1351  * @param {String} format The format the date is in
1352  * @return {Date} The parsed date
1353  * @static
1354  */
1355 Date.parseDate = function(input, format) {
1356     if (Date.parseFunctions[format] == null) {
1357         Date.createParser(format);
1358     }
1359     var func = Date.parseFunctions[format];
1360     return Date[func](input);
1361 };
1362 /**
1363  * @private
1364  */
1365
1366 Date.createParser = function(format) {
1367     var funcName = "parse" + Date.parseFunctions.count++;
1368     var regexNum = Date.parseRegexes.length;
1369     var currentGroup = 1;
1370     Date.parseFunctions[format] = funcName;
1371
1372     var code = "Date." + funcName + " = function(input){\n"
1373         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1374         + "var d = new Date();\n"
1375         + "y = d.getFullYear();\n"
1376         + "m = d.getMonth();\n"
1377         + "d = d.getDate();\n"
1378         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1379         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1380         + "if (results && results.length > 0) {";
1381     var regex = "";
1382
1383     var special = false;
1384     var ch = '';
1385     for (var i = 0; i < format.length; ++i) {
1386         ch = format.charAt(i);
1387         if (!special && ch == "\\") {
1388             special = true;
1389         }
1390         else if (special) {
1391             special = false;
1392             regex += String.escape(ch);
1393         }
1394         else {
1395             var obj = Date.formatCodeToRegex(ch, currentGroup);
1396             currentGroup += obj.g;
1397             regex += obj.s;
1398             if (obj.g && obj.c) {
1399                 code += obj.c;
1400             }
1401         }
1402     }
1403
1404     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1405         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1406         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1407         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1408         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1409         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1410         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1411         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1412         + "else if (y >= 0 && m >= 0)\n"
1413         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1414         + "else if (y >= 0)\n"
1415         + "{v = new Date(y); v.setFullYear(y);}\n"
1416         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1417         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1418         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1419         + ";}";
1420
1421     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1422     /** eval:var:zzzzzzzzzzzzz */
1423     eval(code);
1424 };
1425
1426 // private
1427 Date.formatCodeToRegex = function(character, currentGroup) {
1428     switch (character) {
1429     case "D":
1430         return {g:0,
1431         c:null,
1432         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1433     case "j":
1434         return {g:1,
1435             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{1,2})"}; // day of month without leading zeroes
1437     case "d":
1438         return {g:1,
1439             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1440             s:"(\\d{2})"}; // day of month with leading zeroes
1441     case "l":
1442         return {g:0,
1443             c:null,
1444             s:"(?:" + Date.dayNames.join("|") + ")"};
1445     case "S":
1446         return {g:0,
1447             c:null,
1448             s:"(?:st|nd|rd|th)"};
1449     case "w":
1450         return {g:0,
1451             c:null,
1452             s:"\\d"};
1453     case "z":
1454         return {g:0,
1455             c:null,
1456             s:"(?:\\d{1,3})"};
1457     case "W":
1458         return {g:0,
1459             c:null,
1460             s:"(?:\\d{2})"};
1461     case "F":
1462         return {g:1,
1463             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1464             s:"(" + Date.monthNames.join("|") + ")"};
1465     case "M":
1466         return {g:1,
1467             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1468             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1469     case "n":
1470         return {g:1,
1471             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1472             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1473     case "m":
1474         return {g:1,
1475             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1476             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477     case "t":
1478         return {g:0,
1479             c:null,
1480             s:"\\d{1,2}"};
1481     case "L":
1482         return {g:0,
1483             c:null,
1484             s:"(?:1|0)"};
1485     case "Y":
1486         return {g:1,
1487             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1488             s:"(\\d{4})"};
1489     case "y":
1490         return {g:1,
1491             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1492                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1493             s:"(\\d{1,2})"};
1494     case "a":
1495         return {g:1,
1496             c:"if (results[" + currentGroup + "] == 'am') {\n"
1497                 + "if (h == 12) { h = 0; }\n"
1498                 + "} else { if (h < 12) { h += 12; }}",
1499             s:"(am|pm)"};
1500     case "A":
1501         return {g:1,
1502             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1503                 + "if (h == 12) { h = 0; }\n"
1504                 + "} else { if (h < 12) { h += 12; }}",
1505             s:"(AM|PM)"};
1506     case "g":
1507     case "G":
1508         return {g:1,
1509             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1510             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1511     case "h":
1512     case "H":
1513         return {g:1,
1514             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1515             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1516     case "i":
1517         return {g:1,
1518             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1519             s:"(\\d{2})"};
1520     case "s":
1521         return {g:1,
1522             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1523             s:"(\\d{2})"};
1524     case "O":
1525         return {g:1,
1526             c:[
1527                 "o = results[", currentGroup, "];\n",
1528                 "var sn = o.substring(0,1);\n", // get + / - sign
1529                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1530                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1531                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1532                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1533             ].join(""),
1534             s:"([+\-]\\d{2,4})"};
1535     
1536     
1537     case "P":
1538         return {g:1,
1539                 c:[
1540                    "o = results[", currentGroup, "];\n",
1541                    "var sn = o.substring(0,1);\n",
1542                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1543                    "var mn = o.substring(4,6) % 60;\n",
1544                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1545                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1546             ].join(""),
1547             s:"([+\-]\\d{4})"};
1548     case "T":
1549         return {g:0,
1550             c:null,
1551             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1552     case "Z":
1553         return {g:1,
1554             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1555                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1556             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1557     default:
1558         return {g:0,
1559             c:null,
1560             s:String.escape(character)};
1561     }
1562 };
1563
1564 /**
1565  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1566  * @return {String} The abbreviated timezone name (e.g. 'CST')
1567  */
1568 Date.prototype.getTimezone = function() {
1569     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1570 };
1571
1572 /**
1573  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1574  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1575  */
1576 Date.prototype.getGMTOffset = function() {
1577     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1578         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1579         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1580 };
1581
1582 /**
1583  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1584  * @return {String} 2-characters representing hours and 2-characters representing minutes
1585  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1586  */
1587 Date.prototype.getGMTColonOffset = function() {
1588         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1589                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1590                 + ":"
1591                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1592 }
1593
1594 /**
1595  * Get the numeric day number of the year, adjusted for leap year.
1596  * @return {Number} 0 through 364 (365 in leap years)
1597  */
1598 Date.prototype.getDayOfYear = function() {
1599     var num = 0;
1600     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1601     for (var i = 0; i < this.getMonth(); ++i) {
1602         num += Date.daysInMonth[i];
1603     }
1604     return num + this.getDate() - 1;
1605 };
1606
1607 /**
1608  * Get the string representation of the numeric week number of the year
1609  * (equivalent to the format specifier 'W').
1610  * @return {String} '00' through '52'
1611  */
1612 Date.prototype.getWeekOfYear = function() {
1613     // Skip to Thursday of this week
1614     var now = this.getDayOfYear() + (4 - this.getDay());
1615     // Find the first Thursday of the year
1616     var jan1 = new Date(this.getFullYear(), 0, 1);
1617     var then = (7 - jan1.getDay() + 4);
1618     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1619 };
1620
1621 /**
1622  * Whether or not the current date is in a leap year.
1623  * @return {Boolean} True if the current date is in a leap year, else false
1624  */
1625 Date.prototype.isLeapYear = function() {
1626     var year = this.getFullYear();
1627     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1628 };
1629
1630 /**
1631  * Get the first day of the current month, adjusted for leap year.  The returned value
1632  * is the numeric day index within the week (0-6) which can be used in conjunction with
1633  * the {@link #monthNames} array to retrieve the textual day name.
1634  * Example:
1635  *<pre><code>
1636 var dt = new Date('1/10/2007');
1637 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1638 </code></pre>
1639  * @return {Number} The day number (0-6)
1640  */
1641 Date.prototype.getFirstDayOfMonth = function() {
1642     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1643     return (day < 0) ? (day + 7) : day;
1644 };
1645
1646 /**
1647  * Get the last day of the current month, adjusted for leap year.  The returned value
1648  * is the numeric day index within the week (0-6) which can be used in conjunction with
1649  * the {@link #monthNames} array to retrieve the textual day name.
1650  * Example:
1651  *<pre><code>
1652 var dt = new Date('1/10/2007');
1653 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1654 </code></pre>
1655  * @return {Number} The day number (0-6)
1656  */
1657 Date.prototype.getLastDayOfMonth = function() {
1658     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1659     return (day < 0) ? (day + 7) : day;
1660 };
1661
1662
1663 /**
1664  * Get the first date of this date's month
1665  * @return {Date}
1666  */
1667 Date.prototype.getFirstDateOfMonth = function() {
1668     return new Date(this.getFullYear(), this.getMonth(), 1);
1669 };
1670
1671 /**
1672  * Get the last date of this date's month
1673  * @return {Date}
1674  */
1675 Date.prototype.getLastDateOfMonth = function() {
1676     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1677 };
1678 /**
1679  * Get the number of days in the current month, adjusted for leap year.
1680  * @return {Number} The number of days in the month
1681  */
1682 Date.prototype.getDaysInMonth = function() {
1683     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1684     return Date.daysInMonth[this.getMonth()];
1685 };
1686
1687 /**
1688  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1689  * @return {String} 'st, 'nd', 'rd' or 'th'
1690  */
1691 Date.prototype.getSuffix = function() {
1692     switch (this.getDate()) {
1693         case 1:
1694         case 21:
1695         case 31:
1696             return "st";
1697         case 2:
1698         case 22:
1699             return "nd";
1700         case 3:
1701         case 23:
1702             return "rd";
1703         default:
1704             return "th";
1705     }
1706 };
1707
1708 // private
1709 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1710
1711 /**
1712  * An array of textual month names.
1713  * Override these values for international dates, for example...
1714  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1715  * @type Array
1716  * @static
1717  */
1718 Date.monthNames =
1719    ["January",
1720     "February",
1721     "March",
1722     "April",
1723     "May",
1724     "June",
1725     "July",
1726     "August",
1727     "September",
1728     "October",
1729     "November",
1730     "December"];
1731
1732 /**
1733  * An array of textual day names.
1734  * Override these values for international dates, for example...
1735  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1736  * @type Array
1737  * @static
1738  */
1739 Date.dayNames =
1740    ["Sunday",
1741     "Monday",
1742     "Tuesday",
1743     "Wednesday",
1744     "Thursday",
1745     "Friday",
1746     "Saturday"];
1747
1748 // private
1749 Date.y2kYear = 50;
1750 // private
1751 Date.monthNumbers = {
1752     Jan:0,
1753     Feb:1,
1754     Mar:2,
1755     Apr:3,
1756     May:4,
1757     Jun:5,
1758     Jul:6,
1759     Aug:7,
1760     Sep:8,
1761     Oct:9,
1762     Nov:10,
1763     Dec:11};
1764
1765 /**
1766  * Creates and returns a new Date instance with the exact same date value as the called instance.
1767  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1768  * variable will also be changed.  When the intention is to create a new variable that will not
1769  * modify the original instance, you should create a clone.
1770  *
1771  * Example of correctly cloning a date:
1772  * <pre><code>
1773 //wrong way:
1774 var orig = new Date('10/1/2006');
1775 var copy = orig;
1776 copy.setDate(5);
1777 document.write(orig);  //returns 'Thu Oct 05 2006'!
1778
1779 //correct way:
1780 var orig = new Date('10/1/2006');
1781 var copy = orig.clone();
1782 copy.setDate(5);
1783 document.write(orig);  //returns 'Thu Oct 01 2006'
1784 </code></pre>
1785  * @return {Date} The new Date instance
1786  */
1787 Date.prototype.clone = function() {
1788         return new Date(this.getTime());
1789 };
1790
1791 /**
1792  * Clears any time information from this date
1793  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1794  @return {Date} this or the clone
1795  */
1796 Date.prototype.clearTime = function(clone){
1797     if(clone){
1798         return this.clone().clearTime();
1799     }
1800     this.setHours(0);
1801     this.setMinutes(0);
1802     this.setSeconds(0);
1803     this.setMilliseconds(0);
1804     return this;
1805 };
1806
1807 // private
1808 // safari setMonth is broken -- check that this is only donw once...
1809 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1810     Date.brokenSetMonth = Date.prototype.setMonth;
1811         Date.prototype.setMonth = function(num){
1812                 if(num <= -1){
1813                         var n = Math.ceil(-num);
1814                         var back_year = Math.ceil(n/12);
1815                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1816                         this.setFullYear(this.getFullYear() - back_year);
1817                         return Date.brokenSetMonth.call(this, month);
1818                 } else {
1819                         return Date.brokenSetMonth.apply(this, arguments);
1820                 }
1821         };
1822 }
1823
1824 /** Date interval constant 
1825 * @static 
1826 * @type String */
1827 Date.MILLI = "ms";
1828 /** Date interval constant 
1829 * @static 
1830 * @type String */
1831 Date.SECOND = "s";
1832 /** Date interval constant 
1833 * @static 
1834 * @type String */
1835 Date.MINUTE = "mi";
1836 /** Date interval constant 
1837 * @static 
1838 * @type String */
1839 Date.HOUR = "h";
1840 /** Date interval constant 
1841 * @static 
1842 * @type String */
1843 Date.DAY = "d";
1844 /** Date interval constant 
1845 * @static 
1846 * @type String */
1847 Date.MONTH = "mo";
1848 /** Date interval constant 
1849 * @static 
1850 * @type String */
1851 Date.YEAR = "y";
1852
1853 /**
1854  * Provides a convenient method of performing basic date arithmetic.  This method
1855  * does not modify the Date instance being called - it creates and returns
1856  * a new Date instance containing the resulting date value.
1857  *
1858  * Examples:
1859  * <pre><code>
1860 //Basic usage:
1861 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1862 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1863
1864 //Negative values will subtract correctly:
1865 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1866 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1867
1868 //You can even chain several calls together in one line!
1869 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1870 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1871  </code></pre>
1872  *
1873  * @param {String} interval   A valid date interval enum value
1874  * @param {Number} value      The amount to add to the current date
1875  * @return {Date} The new Date instance
1876  */
1877 Date.prototype.add = function(interval, value){
1878   var d = this.clone();
1879   if (!interval || value === 0) { return d; }
1880   switch(interval.toLowerCase()){
1881     case Date.MILLI:
1882       d.setMilliseconds(this.getMilliseconds() + value);
1883       break;
1884     case Date.SECOND:
1885       d.setSeconds(this.getSeconds() + value);
1886       break;
1887     case Date.MINUTE:
1888       d.setMinutes(this.getMinutes() + value);
1889       break;
1890     case Date.HOUR:
1891       d.setHours(this.getHours() + value);
1892       break;
1893     case Date.DAY:
1894       d.setDate(this.getDate() + value);
1895       break;
1896     case Date.MONTH:
1897       var day = this.getDate();
1898       if(day > 28){
1899           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1900       }
1901       d.setDate(day);
1902       d.setMonth(this.getMonth() + value);
1903       break;
1904     case Date.YEAR:
1905       d.setFullYear(this.getFullYear() + value);
1906       break;
1907   }
1908   return d;
1909 };
1910 /**
1911  * @class Roo.lib.Dom
1912  * @licence LGPL
1913  * @static
1914  * 
1915  * Dom utils (from YIU afaik)
1916  *
1917  * 
1918  **/
1919 Roo.lib.Dom = {
1920     /**
1921      * Get the view width
1922      * @param {Boolean} full True will get the full document, otherwise it's the view width
1923      * @return {Number} The width
1924      */
1925      
1926     getViewWidth : function(full) {
1927         return full ? this.getDocumentWidth() : this.getViewportWidth();
1928     },
1929     /**
1930      * Get the view height
1931      * @param {Boolean} full True will get the full document, otherwise it's the view height
1932      * @return {Number} The height
1933      */
1934     getViewHeight : function(full) {
1935         return full ? this.getDocumentHeight() : this.getViewportHeight();
1936     },
1937     /**
1938      * Get the Full Document height 
1939      * @return {Number} The height
1940      */
1941     getDocumentHeight: function() {
1942         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1943         return Math.max(scrollHeight, this.getViewportHeight());
1944     },
1945     /**
1946      * Get the Full Document width
1947      * @return {Number} The width
1948      */
1949     getDocumentWidth: function() {
1950         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1951         return Math.max(scrollWidth, this.getViewportWidth());
1952     },
1953     /**
1954      * Get the Window Viewport height
1955      * @return {Number} The height
1956      */
1957     getViewportHeight: function() {
1958         var height = self.innerHeight;
1959         var mode = document.compatMode;
1960
1961         if ((mode || Roo.isIE) && !Roo.isOpera) {
1962             height = (mode == "CSS1Compat") ?
1963                      document.documentElement.clientHeight :
1964                      document.body.clientHeight;
1965         }
1966
1967         return height;
1968     },
1969     /**
1970      * Get the Window Viewport width
1971      * @return {Number} The width
1972      */
1973     getViewportWidth: function() {
1974         var width = self.innerWidth;
1975         var mode = document.compatMode;
1976
1977         if (mode || Roo.isIE) {
1978             width = (mode == "CSS1Compat") ?
1979                     document.documentElement.clientWidth :
1980                     document.body.clientWidth;
1981         }
1982         return width;
1983     },
1984
1985     isAncestor : function(p, c) {
1986         p = Roo.getDom(p);
1987         c = Roo.getDom(c);
1988         if (!p || !c) {
1989             return false;
1990         }
1991
1992         if (p.contains && !Roo.isSafari) {
1993             return p.contains(c);
1994         } else if (p.compareDocumentPosition) {
1995             return !!(p.compareDocumentPosition(c) & 16);
1996         } else {
1997             var parent = c.parentNode;
1998             while (parent) {
1999                 if (parent == p) {
2000                     return true;
2001                 }
2002                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2003                     return false;
2004                 }
2005                 parent = parent.parentNode;
2006             }
2007             return false;
2008         }
2009     },
2010
2011     getRegion : function(el) {
2012         return Roo.lib.Region.getRegion(el);
2013     },
2014
2015     getY : function(el) {
2016         return this.getXY(el)[1];
2017     },
2018
2019     getX : function(el) {
2020         return this.getXY(el)[0];
2021     },
2022
2023     getXY : function(el) {
2024         var p, pe, b, scroll, bd = document.body;
2025         el = Roo.getDom(el);
2026         var fly = Roo.lib.AnimBase.fly;
2027         if (el.getBoundingClientRect) {
2028             b = el.getBoundingClientRect();
2029             scroll = fly(document).getScroll();
2030             return [b.left + scroll.left, b.top + scroll.top];
2031         }
2032         var x = 0, y = 0;
2033
2034         p = el;
2035
2036         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2037
2038         while (p) {
2039
2040             x += p.offsetLeft;
2041             y += p.offsetTop;
2042
2043             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2044                 hasAbsolute = true;
2045             }
2046
2047             if (Roo.isGecko) {
2048                 pe = fly(p);
2049
2050                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2051                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2052
2053
2054                 x += bl;
2055                 y += bt;
2056
2057
2058                 if (p != el && pe.getStyle('overflow') != 'visible') {
2059                     x += bl;
2060                     y += bt;
2061                 }
2062             }
2063             p = p.offsetParent;
2064         }
2065
2066         if (Roo.isSafari && hasAbsolute) {
2067             x -= bd.offsetLeft;
2068             y -= bd.offsetTop;
2069         }
2070
2071         if (Roo.isGecko && !hasAbsolute) {
2072             var dbd = fly(bd);
2073             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2074             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2075         }
2076
2077         p = el.parentNode;
2078         while (p && p != bd) {
2079             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2080                 x -= p.scrollLeft;
2081                 y -= p.scrollTop;
2082             }
2083             p = p.parentNode;
2084         }
2085         return [x, y];
2086     },
2087  
2088   
2089
2090
2091     setXY : function(el, xy) {
2092         el = Roo.fly(el, '_setXY');
2093         el.position();
2094         var pts = el.translatePoints(xy);
2095         if (xy[0] !== false) {
2096             el.dom.style.left = pts.left + "px";
2097         }
2098         if (xy[1] !== false) {
2099             el.dom.style.top = pts.top + "px";
2100         }
2101     },
2102
2103     setX : function(el, x) {
2104         this.setXY(el, [x, false]);
2105     },
2106
2107     setY : function(el, y) {
2108         this.setXY(el, [false, y]);
2109     }
2110 };
2111 /*
2112  * Portions of this file are based on pieces of Yahoo User Interface Library
2113  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2114  * YUI licensed under the BSD License:
2115  * http://developer.yahoo.net/yui/license.txt
2116  * <script type="text/javascript">
2117  *
2118  */
2119
2120 Roo.lib.Event = function() {
2121     var loadComplete = false;
2122     var listeners = [];
2123     var unloadListeners = [];
2124     var retryCount = 0;
2125     var onAvailStack = [];
2126     var counter = 0;
2127     var lastError = null;
2128
2129     return {
2130         POLL_RETRYS: 200,
2131         POLL_INTERVAL: 20,
2132         EL: 0,
2133         TYPE: 1,
2134         FN: 2,
2135         WFN: 3,
2136         OBJ: 3,
2137         ADJ_SCOPE: 4,
2138         _interval: null,
2139
2140         startInterval: function() {
2141             if (!this._interval) {
2142                 var self = this;
2143                 var callback = function() {
2144                     self._tryPreloadAttach();
2145                 };
2146                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2147
2148             }
2149         },
2150
2151         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2152             onAvailStack.push({ id:         p_id,
2153                 fn:         p_fn,
2154                 obj:        p_obj,
2155                 override:   p_override,
2156                 checkReady: false    });
2157
2158             retryCount = this.POLL_RETRYS;
2159             this.startInterval();
2160         },
2161
2162
2163         addListener: function(el, eventName, fn) {
2164             el = Roo.getDom(el);
2165             if (!el || !fn) {
2166                 return false;
2167             }
2168
2169             if ("unload" == eventName) {
2170                 unloadListeners[unloadListeners.length] =
2171                 [el, eventName, fn];
2172                 return true;
2173             }
2174
2175             var wrappedFn = function(e) {
2176                 return fn(Roo.lib.Event.getEvent(e));
2177             };
2178
2179             var li = [el, eventName, fn, wrappedFn];
2180
2181             var index = listeners.length;
2182             listeners[index] = li;
2183
2184             this.doAdd(el, eventName, wrappedFn, false);
2185             return true;
2186
2187         },
2188
2189
2190         removeListener: function(el, eventName, fn) {
2191             var i, len;
2192
2193             el = Roo.getDom(el);
2194
2195             if(!fn) {
2196                 return this.purgeElement(el, false, eventName);
2197             }
2198
2199
2200             if ("unload" == eventName) {
2201
2202                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2203                     var li = unloadListeners[i];
2204                     if (li &&
2205                         li[0] == el &&
2206                         li[1] == eventName &&
2207                         li[2] == fn) {
2208                         unloadListeners.splice(i, 1);
2209                         return true;
2210                     }
2211                 }
2212
2213                 return false;
2214             }
2215
2216             var cacheItem = null;
2217
2218
2219             var index = arguments[3];
2220
2221             if ("undefined" == typeof index) {
2222                 index = this._getCacheIndex(el, eventName, fn);
2223             }
2224
2225             if (index >= 0) {
2226                 cacheItem = listeners[index];
2227             }
2228
2229             if (!el || !cacheItem) {
2230                 return false;
2231             }
2232
2233             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2234
2235             delete listeners[index][this.WFN];
2236             delete listeners[index][this.FN];
2237             listeners.splice(index, 1);
2238
2239             return true;
2240
2241         },
2242
2243
2244         getTarget: function(ev, resolveTextNode) {
2245             ev = ev.browserEvent || ev;
2246             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2247             var t = ev.target || ev.srcElement;
2248             return this.resolveTextNode(t);
2249         },
2250
2251
2252         resolveTextNode: function(node) {
2253             if (Roo.isSafari && node && 3 == node.nodeType) {
2254                 return node.parentNode;
2255             } else {
2256                 return node;
2257             }
2258         },
2259
2260
2261         getPageX: function(ev) {
2262             ev = ev.browserEvent || ev;
2263             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2264             var x = ev.pageX;
2265             if (!x && 0 !== x) {
2266                 x = ev.clientX || 0;
2267
2268                 if (Roo.isIE) {
2269                     x += this.getScroll()[1];
2270                 }
2271             }
2272
2273             return x;
2274         },
2275
2276
2277         getPageY: function(ev) {
2278             ev = ev.browserEvent || ev;
2279             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2280             var y = ev.pageY;
2281             if (!y && 0 !== y) {
2282                 y = ev.clientY || 0;
2283
2284                 if (Roo.isIE) {
2285                     y += this.getScroll()[0];
2286                 }
2287             }
2288
2289
2290             return y;
2291         },
2292
2293
2294         getXY: function(ev) {
2295             ev = ev.browserEvent || ev;
2296             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2297             return [this.getPageX(ev), this.getPageY(ev)];
2298         },
2299
2300
2301         getRelatedTarget: function(ev) {
2302             ev = ev.browserEvent || ev;
2303             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2304             var t = ev.relatedTarget;
2305             if (!t) {
2306                 if (ev.type == "mouseout") {
2307                     t = ev.toElement;
2308                 } else if (ev.type == "mouseover") {
2309                     t = ev.fromElement;
2310                 }
2311             }
2312
2313             return this.resolveTextNode(t);
2314         },
2315
2316
2317         getTime: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2320             if (!ev.time) {
2321                 var t = new Date().getTime();
2322                 try {
2323                     ev.time = t;
2324                 } catch(ex) {
2325                     this.lastError = ex;
2326                     return t;
2327                 }
2328             }
2329
2330             return ev.time;
2331         },
2332
2333
2334         stopEvent: function(ev) {
2335             this.stopPropagation(ev);
2336             this.preventDefault(ev);
2337         },
2338
2339
2340         stopPropagation: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             if (ev.stopPropagation) {
2343                 ev.stopPropagation();
2344             } else {
2345                 ev.cancelBubble = true;
2346             }
2347         },
2348
2349
2350         preventDefault: function(ev) {
2351             ev = ev.browserEvent || ev;
2352             if(ev.preventDefault) {
2353                 ev.preventDefault();
2354             } else {
2355                 ev.returnValue = false;
2356             }
2357         },
2358
2359
2360         getEvent: function(e) {
2361             var ev = e || window.event;
2362             if (!ev) {
2363                 var c = this.getEvent.caller;
2364                 while (c) {
2365                     ev = c.arguments[0];
2366                     if (ev && Event == ev.constructor) {
2367                         break;
2368                     }
2369                     c = c.caller;
2370                 }
2371             }
2372             return ev;
2373         },
2374
2375
2376         getCharCode: function(ev) {
2377             ev = ev.browserEvent || ev;
2378             return ev.charCode || ev.keyCode || 0;
2379         },
2380
2381
2382         _getCacheIndex: function(el, eventName, fn) {
2383             for (var i = 0,len = listeners.length; i < len; ++i) {
2384                 var li = listeners[i];
2385                 if (li &&
2386                     li[this.FN] == fn &&
2387                     li[this.EL] == el &&
2388                     li[this.TYPE] == eventName) {
2389                     return i;
2390                 }
2391             }
2392
2393             return -1;
2394         },
2395
2396
2397         elCache: {},
2398
2399
2400         getEl: function(id) {
2401             return document.getElementById(id);
2402         },
2403
2404
2405         clearCache: function() {
2406         },
2407
2408
2409         _load: function(e) {
2410             loadComplete = true;
2411             var EU = Roo.lib.Event;
2412
2413
2414             if (Roo.isIE) {
2415                 EU.doRemove(window, "load", EU._load);
2416             }
2417         },
2418
2419
2420         _tryPreloadAttach: function() {
2421
2422             if (this.locked) {
2423                 return false;
2424             }
2425
2426             this.locked = true;
2427
2428
2429             var tryAgain = !loadComplete;
2430             if (!tryAgain) {
2431                 tryAgain = (retryCount > 0);
2432             }
2433
2434
2435             var notAvail = [];
2436             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2437                 var item = onAvailStack[i];
2438                 if (item) {
2439                     var el = this.getEl(item.id);
2440
2441                     if (el) {
2442                         if (!item.checkReady ||
2443                             loadComplete ||
2444                             el.nextSibling ||
2445                             (document && document.body)) {
2446
2447                             var scope = el;
2448                             if (item.override) {
2449                                 if (item.override === true) {
2450                                     scope = item.obj;
2451                                 } else {
2452                                     scope = item.override;
2453                                 }
2454                             }
2455                             item.fn.call(scope, item.obj);
2456                             onAvailStack[i] = null;
2457                         }
2458                     } else {
2459                         notAvail.push(item);
2460                     }
2461                 }
2462             }
2463
2464             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2465
2466             if (tryAgain) {
2467
2468                 this.startInterval();
2469             } else {
2470                 clearInterval(this._interval);
2471                 this._interval = null;
2472             }
2473
2474             this.locked = false;
2475
2476             return true;
2477
2478         },
2479
2480
2481         purgeElement: function(el, recurse, eventName) {
2482             var elListeners = this.getListeners(el, eventName);
2483             if (elListeners) {
2484                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2485                     var l = elListeners[i];
2486                     this.removeListener(el, l.type, l.fn);
2487                 }
2488             }
2489
2490             if (recurse && el && el.childNodes) {
2491                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2492                     this.purgeElement(el.childNodes[i], recurse, eventName);
2493                 }
2494             }
2495         },
2496
2497
2498         getListeners: function(el, eventName) {
2499             var results = [], searchLists;
2500             if (!eventName) {
2501                 searchLists = [listeners, unloadListeners];
2502             } else if (eventName == "unload") {
2503                 searchLists = [unloadListeners];
2504             } else {
2505                 searchLists = [listeners];
2506             }
2507
2508             for (var j = 0; j < searchLists.length; ++j) {
2509                 var searchList = searchLists[j];
2510                 if (searchList && searchList.length > 0) {
2511                     for (var i = 0,len = searchList.length; i < len; ++i) {
2512                         var l = searchList[i];
2513                         if (l && l[this.EL] === el &&
2514                             (!eventName || eventName === l[this.TYPE])) {
2515                             results.push({
2516                                 type:   l[this.TYPE],
2517                                 fn:     l[this.FN],
2518                                 obj:    l[this.OBJ],
2519                                 adjust: l[this.ADJ_SCOPE],
2520                                 index:  i
2521                             });
2522                         }
2523                     }
2524                 }
2525             }
2526
2527             return (results.length) ? results : null;
2528         },
2529
2530
2531         _unload: function(e) {
2532
2533             var EU = Roo.lib.Event, i, j, l, len, index;
2534
2535             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2536                 l = unloadListeners[i];
2537                 if (l) {
2538                     var scope = window;
2539                     if (l[EU.ADJ_SCOPE]) {
2540                         if (l[EU.ADJ_SCOPE] === true) {
2541                             scope = l[EU.OBJ];
2542                         } else {
2543                             scope = l[EU.ADJ_SCOPE];
2544                         }
2545                     }
2546                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2547                     unloadListeners[i] = null;
2548                     l = null;
2549                     scope = null;
2550                 }
2551             }
2552
2553             unloadListeners = null;
2554
2555             if (listeners && listeners.length > 0) {
2556                 j = listeners.length;
2557                 while (j) {
2558                     index = j - 1;
2559                     l = listeners[index];
2560                     if (l) {
2561                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2562                                 l[EU.FN], index);
2563                     }
2564                     j = j - 1;
2565                 }
2566                 l = null;
2567
2568                 EU.clearCache();
2569             }
2570
2571             EU.doRemove(window, "unload", EU._unload);
2572
2573         },
2574
2575
2576         getScroll: function() {
2577             var dd = document.documentElement, db = document.body;
2578             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2579                 return [dd.scrollTop, dd.scrollLeft];
2580             } else if (db) {
2581                 return [db.scrollTop, db.scrollLeft];
2582             } else {
2583                 return [0, 0];
2584             }
2585         },
2586
2587
2588         doAdd: function () {
2589             if (window.addEventListener) {
2590                 return function(el, eventName, fn, capture) {
2591                     el.addEventListener(eventName, fn, (capture));
2592                 };
2593             } else if (window.attachEvent) {
2594                 return function(el, eventName, fn, capture) {
2595                     el.attachEvent("on" + eventName, fn);
2596                 };
2597             } else {
2598                 return function() {
2599                 };
2600             }
2601         }(),
2602
2603
2604         doRemove: function() {
2605             if (window.removeEventListener) {
2606                 return function (el, eventName, fn, capture) {
2607                     el.removeEventListener(eventName, fn, (capture));
2608                 };
2609             } else if (window.detachEvent) {
2610                 return function (el, eventName, fn) {
2611                     el.detachEvent("on" + eventName, fn);
2612                 };
2613             } else {
2614                 return function() {
2615                 };
2616             }
2617         }()
2618     };
2619     
2620 }();
2621 (function() {     
2622    
2623     var E = Roo.lib.Event;
2624     E.on = E.addListener;
2625     E.un = E.removeListener;
2626
2627     if (document && document.body) {
2628         E._load();
2629     } else {
2630         E.doAdd(window, "load", E._load);
2631     }
2632     E.doAdd(window, "unload", E._unload);
2633     E._tryPreloadAttach();
2634 })();
2635
2636  
2637
2638 (function() {
2639     /**
2640      * @class Roo.lib.Ajax
2641      *
2642      * provide a simple Ajax request utility functions
2643      * 
2644      * Portions of this file are based on pieces of Yahoo User Interface Library
2645     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2646     * YUI licensed under the BSD License:
2647     * http://developer.yahoo.net/yui/license.txt
2648     * <script type="text/javascript">
2649     *
2650      *
2651      */
2652     Roo.lib.Ajax = {
2653         /**
2654          * @static 
2655          */
2656         request : function(method, uri, cb, data, options) {
2657             if(options){
2658                 var hs = options.headers;
2659                 if(hs){
2660                     for(var h in hs){
2661                         if(hs.hasOwnProperty(h)){
2662                             this.initHeader(h, hs[h], false);
2663                         }
2664                     }
2665                 }
2666                 if(options.xmlData){
2667                     this.initHeader('Content-Type', 'text/xml', false);
2668                     method = 'POST';
2669                     data = options.xmlData;
2670                 }
2671             }
2672
2673             return this.asyncRequest(method, uri, cb, data);
2674         },
2675         /**
2676          * serialize a form
2677          *
2678          * @static
2679          * @param {DomForm} form element
2680          * @return {String} urlencode form output.
2681          */
2682         serializeForm : function(form) {
2683             if(typeof form == 'string') {
2684                 form = (document.getElementById(form) || document.forms[form]);
2685             }
2686
2687             var el, name, val, disabled, data = '', hasSubmit = false;
2688             for (var i = 0; i < form.elements.length; i++) {
2689                 el = form.elements[i];
2690                 disabled = form.elements[i].disabled;
2691                 name = form.elements[i].name;
2692                 val = form.elements[i].value;
2693
2694                 if (!disabled && name){
2695                     switch (el.type)
2696                             {
2697                         case 'select-one':
2698                         case 'select-multiple':
2699                             for (var j = 0; j < el.options.length; j++) {
2700                                 if (el.options[j].selected) {
2701                                     if (Roo.isIE) {
2702                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2703                                     }
2704                                     else {
2705                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2706                                     }
2707                                 }
2708                             }
2709                             break;
2710                         case 'radio':
2711                         case 'checkbox':
2712                             if (el.checked) {
2713                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2714                             }
2715                             break;
2716                         case 'file':
2717
2718                         case undefined:
2719
2720                         case 'reset':
2721
2722                         case 'button':
2723
2724                             break;
2725                         case 'submit':
2726                             if(hasSubmit == false) {
2727                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728                                 hasSubmit = true;
2729                             }
2730                             break;
2731                         default:
2732                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2733                             break;
2734                     }
2735                 }
2736             }
2737             data = data.substr(0, data.length - 1);
2738             return data;
2739         },
2740
2741         headers:{},
2742
2743         hasHeaders:false,
2744
2745         useDefaultHeader:true,
2746
2747         defaultPostHeader:'application/x-www-form-urlencoded',
2748
2749         useDefaultXhrHeader:true,
2750
2751         defaultXhrHeader:'XMLHttpRequest',
2752
2753         hasDefaultHeaders:true,
2754
2755         defaultHeaders:{},
2756
2757         poll:{},
2758
2759         timeout:{},
2760
2761         pollInterval:50,
2762
2763         transactionId:0,
2764
2765         setProgId:function(id)
2766         {
2767             this.activeX.unshift(id);
2768         },
2769
2770         setDefaultPostHeader:function(b)
2771         {
2772             this.useDefaultHeader = b;
2773         },
2774
2775         setDefaultXhrHeader:function(b)
2776         {
2777             this.useDefaultXhrHeader = b;
2778         },
2779
2780         setPollingInterval:function(i)
2781         {
2782             if (typeof i == 'number' && isFinite(i)) {
2783                 this.pollInterval = i;
2784             }
2785         },
2786
2787         createXhrObject:function(transactionId)
2788         {
2789             var obj,http;
2790             try
2791             {
2792
2793                 http = new XMLHttpRequest();
2794
2795                 obj = { conn:http, tId:transactionId };
2796             }
2797             catch(e)
2798             {
2799                 for (var i = 0; i < this.activeX.length; ++i) {
2800                     try
2801                     {
2802
2803                         http = new ActiveXObject(this.activeX[i]);
2804
2805                         obj = { conn:http, tId:transactionId };
2806                         break;
2807                     }
2808                     catch(e) {
2809                     }
2810                 }
2811             }
2812             finally
2813             {
2814                 return obj;
2815             }
2816         },
2817
2818         getConnectionObject:function()
2819         {
2820             var o;
2821             var tId = this.transactionId;
2822
2823             try
2824             {
2825                 o = this.createXhrObject(tId);
2826                 if (o) {
2827                     this.transactionId++;
2828                 }
2829             }
2830             catch(e) {
2831             }
2832             finally
2833             {
2834                 return o;
2835             }
2836         },
2837
2838         asyncRequest:function(method, uri, callback, postData)
2839         {
2840             var o = this.getConnectionObject();
2841
2842             if (!o) {
2843                 return null;
2844             }
2845             else {
2846                 o.conn.open(method, uri, true);
2847
2848                 if (this.useDefaultXhrHeader) {
2849                     if (!this.defaultHeaders['X-Requested-With']) {
2850                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2851                     }
2852                 }
2853
2854                 if(postData && this.useDefaultHeader){
2855                     this.initHeader('Content-Type', this.defaultPostHeader);
2856                 }
2857
2858                  if (this.hasDefaultHeaders || this.hasHeaders) {
2859                     this.setHeader(o);
2860                 }
2861
2862                 this.handleReadyState(o, callback);
2863                 o.conn.send(postData || null);
2864
2865                 return o;
2866             }
2867         },
2868
2869         handleReadyState:function(o, callback)
2870         {
2871             var oConn = this;
2872
2873             if (callback && callback.timeout) {
2874                 
2875                 this.timeout[o.tId] = window.setTimeout(function() {
2876                     oConn.abort(o, callback, true);
2877                 }, callback.timeout);
2878             }
2879
2880             this.poll[o.tId] = window.setInterval(
2881                     function() {
2882                         if (o.conn && o.conn.readyState == 4) {
2883                             window.clearInterval(oConn.poll[o.tId]);
2884                             delete oConn.poll[o.tId];
2885
2886                             if(callback && callback.timeout) {
2887                                 window.clearTimeout(oConn.timeout[o.tId]);
2888                                 delete oConn.timeout[o.tId];
2889                             }
2890
2891                             oConn.handleTransactionResponse(o, callback);
2892                         }
2893                     }
2894                     , this.pollInterval);
2895         },
2896
2897         handleTransactionResponse:function(o, callback, isAbort)
2898         {
2899
2900             if (!callback) {
2901                 this.releaseObject(o);
2902                 return;
2903             }
2904
2905             var httpStatus, responseObject;
2906
2907             try
2908             {
2909                 if (o.conn.status !== undefined && o.conn.status != 0) {
2910                     httpStatus = o.conn.status;
2911                 }
2912                 else {
2913                     httpStatus = 13030;
2914                 }
2915             }
2916             catch(e) {
2917
2918
2919                 httpStatus = 13030;
2920             }
2921
2922             if (httpStatus >= 200 && httpStatus < 300) {
2923                 responseObject = this.createResponseObject(o, callback.argument);
2924                 if (callback.success) {
2925                     if (!callback.scope) {
2926                         callback.success(responseObject);
2927                     }
2928                     else {
2929
2930
2931                         callback.success.apply(callback.scope, [responseObject]);
2932                     }
2933                 }
2934             }
2935             else {
2936                 switch (httpStatus) {
2937
2938                     case 12002:
2939                     case 12029:
2940                     case 12030:
2941                     case 12031:
2942                     case 12152:
2943                     case 13030:
2944                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2945                         if (callback.failure) {
2946                             if (!callback.scope) {
2947                                 callback.failure(responseObject);
2948                             }
2949                             else {
2950                                 callback.failure.apply(callback.scope, [responseObject]);
2951                             }
2952                         }
2953                         break;
2954                     default:
2955                         responseObject = this.createResponseObject(o, callback.argument);
2956                         if (callback.failure) {
2957                             if (!callback.scope) {
2958                                 callback.failure(responseObject);
2959                             }
2960                             else {
2961                                 callback.failure.apply(callback.scope, [responseObject]);
2962                             }
2963                         }
2964                 }
2965             }
2966
2967             this.releaseObject(o);
2968             responseObject = null;
2969         },
2970
2971         createResponseObject:function(o, callbackArg)
2972         {
2973             var obj = {};
2974             var headerObj = {};
2975
2976             try
2977             {
2978                 var headerStr = o.conn.getAllResponseHeaders();
2979                 var header = headerStr.split('\n');
2980                 for (var i = 0; i < header.length; i++) {
2981                     var delimitPos = header[i].indexOf(':');
2982                     if (delimitPos != -1) {
2983                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2984                     }
2985                 }
2986             }
2987             catch(e) {
2988             }
2989
2990             obj.tId = o.tId;
2991             obj.status = o.conn.status;
2992             obj.statusText = o.conn.statusText;
2993             obj.getResponseHeader = headerObj;
2994             obj.getAllResponseHeaders = headerStr;
2995             obj.responseText = o.conn.responseText;
2996             obj.responseXML = o.conn.responseXML;
2997
2998             if (typeof callbackArg !== undefined) {
2999                 obj.argument = callbackArg;
3000             }
3001
3002             return obj;
3003         },
3004
3005         createExceptionObject:function(tId, callbackArg, isAbort)
3006         {
3007             var COMM_CODE = 0;
3008             var COMM_ERROR = 'communication failure';
3009             var ABORT_CODE = -1;
3010             var ABORT_ERROR = 'transaction aborted';
3011
3012             var obj = {};
3013
3014             obj.tId = tId;
3015             if (isAbort) {
3016                 obj.status = ABORT_CODE;
3017                 obj.statusText = ABORT_ERROR;
3018             }
3019             else {
3020                 obj.status = COMM_CODE;
3021                 obj.statusText = COMM_ERROR;
3022             }
3023
3024             if (callbackArg) {
3025                 obj.argument = callbackArg;
3026             }
3027
3028             return obj;
3029         },
3030
3031         initHeader:function(label, value, isDefault)
3032         {
3033             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3034
3035             if (headerObj[label] === undefined) {
3036                 headerObj[label] = value;
3037             }
3038             else {
3039
3040
3041                 headerObj[label] = value + "," + headerObj[label];
3042             }
3043
3044             if (isDefault) {
3045                 this.hasDefaultHeaders = true;
3046             }
3047             else {
3048                 this.hasHeaders = true;
3049             }
3050         },
3051
3052
3053         setHeader:function(o)
3054         {
3055             if (this.hasDefaultHeaders) {
3056                 for (var prop in this.defaultHeaders) {
3057                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3058                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3059                     }
3060                 }
3061             }
3062
3063             if (this.hasHeaders) {
3064                 for (var prop in this.headers) {
3065                     if (this.headers.hasOwnProperty(prop)) {
3066                         o.conn.setRequestHeader(prop, this.headers[prop]);
3067                     }
3068                 }
3069                 this.headers = {};
3070                 this.hasHeaders = false;
3071             }
3072         },
3073
3074         resetDefaultHeaders:function() {
3075             delete this.defaultHeaders;
3076             this.defaultHeaders = {};
3077             this.hasDefaultHeaders = false;
3078         },
3079
3080         abort:function(o, callback, isTimeout)
3081         {
3082             if(this.isCallInProgress(o)) {
3083                 o.conn.abort();
3084                 window.clearInterval(this.poll[o.tId]);
3085                 delete this.poll[o.tId];
3086                 if (isTimeout) {
3087                     delete this.timeout[o.tId];
3088                 }
3089
3090                 this.handleTransactionResponse(o, callback, true);
3091
3092                 return true;
3093             }
3094             else {
3095                 return false;
3096             }
3097         },
3098
3099
3100         isCallInProgress:function(o)
3101         {
3102             if (o && o.conn) {
3103                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3104             }
3105             else {
3106
3107                 return false;
3108             }
3109         },
3110
3111
3112         releaseObject:function(o)
3113         {
3114
3115             o.conn = null;
3116
3117             o = null;
3118         },
3119
3120         activeX:[
3121         'MSXML2.XMLHTTP.3.0',
3122         'MSXML2.XMLHTTP',
3123         'Microsoft.XMLHTTP'
3124         ]
3125
3126
3127     };
3128 })();/*
3129  * Portions of this file are based on pieces of Yahoo User Interface Library
3130  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3131  * YUI licensed under the BSD License:
3132  * http://developer.yahoo.net/yui/license.txt
3133  * <script type="text/javascript">
3134  *
3135  */
3136
3137 Roo.lib.Region = function(t, r, b, l) {
3138     this.top = t;
3139     this[1] = t;
3140     this.right = r;
3141     this.bottom = b;
3142     this.left = l;
3143     this[0] = l;
3144 };
3145
3146
3147 Roo.lib.Region.prototype = {
3148     contains : function(region) {
3149         return ( region.left >= this.left &&
3150                  region.right <= this.right &&
3151                  region.top >= this.top &&
3152                  region.bottom <= this.bottom    );
3153
3154     },
3155
3156     getArea : function() {
3157         return ( (this.bottom - this.top) * (this.right - this.left) );
3158     },
3159
3160     intersect : function(region) {
3161         var t = Math.max(this.top, region.top);
3162         var r = Math.min(this.right, region.right);
3163         var b = Math.min(this.bottom, region.bottom);
3164         var l = Math.max(this.left, region.left);
3165
3166         if (b >= t && r >= l) {
3167             return new Roo.lib.Region(t, r, b, l);
3168         } else {
3169             return null;
3170         }
3171     },
3172     union : function(region) {
3173         var t = Math.min(this.top, region.top);
3174         var r = Math.max(this.right, region.right);
3175         var b = Math.max(this.bottom, region.bottom);
3176         var l = Math.min(this.left, region.left);
3177
3178         return new Roo.lib.Region(t, r, b, l);
3179     },
3180
3181     adjust : function(t, l, b, r) {
3182         this.top += t;
3183         this.left += l;
3184         this.right += r;
3185         this.bottom += b;
3186         return this;
3187     }
3188 };
3189
3190 Roo.lib.Region.getRegion = function(el) {
3191     var p = Roo.lib.Dom.getXY(el);
3192
3193     var t = p[1];
3194     var r = p[0] + el.offsetWidth;
3195     var b = p[1] + el.offsetHeight;
3196     var l = p[0];
3197
3198     return new Roo.lib.Region(t, r, b, l);
3199 };
3200 /*
3201  * Portions of this file are based on pieces of Yahoo User Interface Library
3202  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3203  * YUI licensed under the BSD License:
3204  * http://developer.yahoo.net/yui/license.txt
3205  * <script type="text/javascript">
3206  *
3207  */
3208 //@@dep Roo.lib.Region
3209
3210
3211 Roo.lib.Point = function(x, y) {
3212     if (x instanceof Array) {
3213         y = x[1];
3214         x = x[0];
3215     }
3216     this.x = this.right = this.left = this[0] = x;
3217     this.y = this.top = this.bottom = this[1] = y;
3218 };
3219
3220 Roo.lib.Point.prototype = new Roo.lib.Region();
3221 /*
3222  * Portions of this file are based on pieces of Yahoo User Interface Library
3223  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3224  * YUI licensed under the BSD License:
3225  * http://developer.yahoo.net/yui/license.txt
3226  * <script type="text/javascript">
3227  *
3228  */
3229  
3230 (function() {   
3231
3232     Roo.lib.Anim = {
3233         scroll : function(el, args, duration, easing, cb, scope) {
3234             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3235         },
3236
3237         motion : function(el, args, duration, easing, cb, scope) {
3238             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3239         },
3240
3241         color : function(el, args, duration, easing, cb, scope) {
3242             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3243         },
3244
3245         run : function(el, args, duration, easing, cb, scope, type) {
3246             type = type || Roo.lib.AnimBase;
3247             if (typeof easing == "string") {
3248                 easing = Roo.lib.Easing[easing];
3249             }
3250             var anim = new type(el, args, duration, easing);
3251             anim.animateX(function() {
3252                 Roo.callback(cb, scope);
3253             });
3254             return anim;
3255         }
3256     };
3257 })();/*
3258  * Portions of this file are based on pieces of Yahoo User Interface Library
3259  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3260  * YUI licensed under the BSD License:
3261  * http://developer.yahoo.net/yui/license.txt
3262  * <script type="text/javascript">
3263  *
3264  */
3265
3266 (function() {    
3267     var libFlyweight;
3268     
3269     function fly(el) {
3270         if (!libFlyweight) {
3271             libFlyweight = new Roo.Element.Flyweight();
3272         }
3273         libFlyweight.dom = el;
3274         return libFlyweight;
3275     }
3276
3277     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3278     
3279    
3280     
3281     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3282         if (el) {
3283             this.init(el, attributes, duration, method);
3284         }
3285     };
3286
3287     Roo.lib.AnimBase.fly = fly;
3288     
3289     
3290     
3291     Roo.lib.AnimBase.prototype = {
3292
3293         toString: function() {
3294             var el = this.getEl();
3295             var id = el.id || el.tagName;
3296             return ("Anim " + id);
3297         },
3298
3299         patterns: {
3300             noNegatives:        /width|height|opacity|padding/i,
3301             offsetAttribute:  /^((width|height)|(top|left))$/,
3302             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3303             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3304         },
3305
3306
3307         doMethod: function(attr, start, end) {
3308             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3309         },
3310
3311
3312         setAttribute: function(attr, val, unit) {
3313             if (this.patterns.noNegatives.test(attr)) {
3314                 val = (val > 0) ? val : 0;
3315             }
3316
3317             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3318         },
3319
3320
3321         getAttribute: function(attr) {
3322             var el = this.getEl();
3323             var val = fly(el).getStyle(attr);
3324
3325             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3326                 return parseFloat(val);
3327             }
3328
3329             var a = this.patterns.offsetAttribute.exec(attr) || [];
3330             var pos = !!( a[3] );
3331             var box = !!( a[2] );
3332
3333
3334             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3335                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3336             } else {
3337                 val = 0;
3338             }
3339
3340             return val;
3341         },
3342
3343
3344         getDefaultUnit: function(attr) {
3345             if (this.patterns.defaultUnit.test(attr)) {
3346                 return 'px';
3347             }
3348
3349             return '';
3350         },
3351
3352         animateX : function(callback, scope) {
3353             var f = function() {
3354                 this.onComplete.removeListener(f);
3355                 if (typeof callback == "function") {
3356                     callback.call(scope || this, this);
3357                 }
3358             };
3359             this.onComplete.addListener(f, this);
3360             this.animate();
3361         },
3362
3363
3364         setRuntimeAttribute: function(attr) {
3365             var start;
3366             var end;
3367             var attributes = this.attributes;
3368
3369             this.runtimeAttributes[attr] = {};
3370
3371             var isset = function(prop) {
3372                 return (typeof prop !== 'undefined');
3373             };
3374
3375             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3376                 return false;
3377             }
3378
3379             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3380
3381
3382             if (isset(attributes[attr]['to'])) {
3383                 end = attributes[attr]['to'];
3384             } else if (isset(attributes[attr]['by'])) {
3385                 if (start.constructor == Array) {
3386                     end = [];
3387                     for (var i = 0, len = start.length; i < len; ++i) {
3388                         end[i] = start[i] + attributes[attr]['by'][i];
3389                     }
3390                 } else {
3391                     end = start + attributes[attr]['by'];
3392                 }
3393             }
3394
3395             this.runtimeAttributes[attr].start = start;
3396             this.runtimeAttributes[attr].end = end;
3397
3398
3399             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3400         },
3401
3402
3403         init: function(el, attributes, duration, method) {
3404
3405             var isAnimated = false;
3406
3407
3408             var startTime = null;
3409
3410
3411             var actualFrames = 0;
3412
3413
3414             el = Roo.getDom(el);
3415
3416
3417             this.attributes = attributes || {};
3418
3419
3420             this.duration = duration || 1;
3421
3422
3423             this.method = method || Roo.lib.Easing.easeNone;
3424
3425
3426             this.useSeconds = true;
3427
3428
3429             this.currentFrame = 0;
3430
3431
3432             this.totalFrames = Roo.lib.AnimMgr.fps;
3433
3434
3435             this.getEl = function() {
3436                 return el;
3437             };
3438
3439
3440             this.isAnimated = function() {
3441                 return isAnimated;
3442             };
3443
3444
3445             this.getStartTime = function() {
3446                 return startTime;
3447             };
3448
3449             this.runtimeAttributes = {};
3450
3451
3452             this.animate = function() {
3453                 if (this.isAnimated()) {
3454                     return false;
3455                 }
3456
3457                 this.currentFrame = 0;
3458
3459                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3460
3461                 Roo.lib.AnimMgr.registerElement(this);
3462             };
3463
3464
3465             this.stop = function(finish) {
3466                 if (finish) {
3467                     this.currentFrame = this.totalFrames;
3468                     this._onTween.fire();
3469                 }
3470                 Roo.lib.AnimMgr.stop(this);
3471             };
3472
3473             var onStart = function() {
3474                 this.onStart.fire();
3475
3476                 this.runtimeAttributes = {};
3477                 for (var attr in this.attributes) {
3478                     this.setRuntimeAttribute(attr);
3479                 }
3480
3481                 isAnimated = true;
3482                 actualFrames = 0;
3483                 startTime = new Date();
3484             };
3485
3486
3487             var onTween = function() {
3488                 var data = {
3489                     duration: new Date() - this.getStartTime(),
3490                     currentFrame: this.currentFrame
3491                 };
3492
3493                 data.toString = function() {
3494                     return (
3495                             'duration: ' + data.duration +
3496                             ', currentFrame: ' + data.currentFrame
3497                             );
3498                 };
3499
3500                 this.onTween.fire(data);
3501
3502                 var runtimeAttributes = this.runtimeAttributes;
3503
3504                 for (var attr in runtimeAttributes) {
3505                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3506                 }
3507
3508                 actualFrames += 1;
3509             };
3510
3511             var onComplete = function() {
3512                 var actual_duration = (new Date() - startTime) / 1000 ;
3513
3514                 var data = {
3515                     duration: actual_duration,
3516                     frames: actualFrames,
3517                     fps: actualFrames / actual_duration
3518                 };
3519
3520                 data.toString = function() {
3521                     return (
3522                             'duration: ' + data.duration +
3523                             ', frames: ' + data.frames +
3524                             ', fps: ' + data.fps
3525                             );
3526                 };
3527
3528                 isAnimated = false;
3529                 actualFrames = 0;
3530                 this.onComplete.fire(data);
3531             };
3532
3533
3534             this._onStart = new Roo.util.Event(this);
3535             this.onStart = new Roo.util.Event(this);
3536             this.onTween = new Roo.util.Event(this);
3537             this._onTween = new Roo.util.Event(this);
3538             this.onComplete = new Roo.util.Event(this);
3539             this._onComplete = new Roo.util.Event(this);
3540             this._onStart.addListener(onStart);
3541             this._onTween.addListener(onTween);
3542             this._onComplete.addListener(onComplete);
3543         }
3544     };
3545 })();
3546 /*
3547  * Portions of this file are based on pieces of Yahoo User Interface Library
3548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549  * YUI licensed under the BSD License:
3550  * http://developer.yahoo.net/yui/license.txt
3551  * <script type="text/javascript">
3552  *
3553  */
3554
3555 Roo.lib.AnimMgr = new function() {
3556
3557     var thread = null;
3558
3559
3560     var queue = [];
3561
3562
3563     var tweenCount = 0;
3564
3565
3566     this.fps = 1000;
3567
3568
3569     this.delay = 1;
3570
3571
3572     this.registerElement = function(tween) {
3573         queue[queue.length] = tween;
3574         tweenCount += 1;
3575         tween._onStart.fire();
3576         this.start();
3577     };
3578
3579
3580     this.unRegister = function(tween, index) {
3581         tween._onComplete.fire();
3582         index = index || getIndex(tween);
3583         if (index != -1) {
3584             queue.splice(index, 1);
3585         }
3586
3587         tweenCount -= 1;
3588         if (tweenCount <= 0) {
3589             this.stop();
3590         }
3591     };
3592
3593
3594     this.start = function() {
3595         if (thread === null) {
3596             thread = setInterval(this.run, this.delay);
3597         }
3598     };
3599
3600
3601     this.stop = function(tween) {
3602         if (!tween) {
3603             clearInterval(thread);
3604
3605             for (var i = 0, len = queue.length; i < len; ++i) {
3606                 if (queue[0].isAnimated()) {
3607                     this.unRegister(queue[0], 0);
3608                 }
3609             }
3610
3611             queue = [];
3612             thread = null;
3613             tweenCount = 0;
3614         }
3615         else {
3616             this.unRegister(tween);
3617         }
3618     };
3619
3620
3621     this.run = function() {
3622         for (var i = 0, len = queue.length; i < len; ++i) {
3623             var tween = queue[i];
3624             if (!tween || !tween.isAnimated()) {
3625                 continue;
3626             }
3627
3628             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3629             {
3630                 tween.currentFrame += 1;
3631
3632                 if (tween.useSeconds) {
3633                     correctFrame(tween);
3634                 }
3635                 tween._onTween.fire();
3636             }
3637             else {
3638                 Roo.lib.AnimMgr.stop(tween, i);
3639             }
3640         }
3641     };
3642
3643     var getIndex = function(anim) {
3644         for (var i = 0, len = queue.length; i < len; ++i) {
3645             if (queue[i] == anim) {
3646                 return i;
3647             }
3648         }
3649         return -1;
3650     };
3651
3652
3653     var correctFrame = function(tween) {
3654         var frames = tween.totalFrames;
3655         var frame = tween.currentFrame;
3656         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3657         var elapsed = (new Date() - tween.getStartTime());
3658         var tweak = 0;
3659
3660         if (elapsed < tween.duration * 1000) {
3661             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3662         } else {
3663             tweak = frames - (frame + 1);
3664         }
3665         if (tweak > 0 && isFinite(tweak)) {
3666             if (tween.currentFrame + tweak >= frames) {
3667                 tweak = frames - (frame + 1);
3668             }
3669
3670             tween.currentFrame += tweak;
3671         }
3672     };
3673 };
3674
3675     /*
3676  * Portions of this file are based on pieces of Yahoo User Interface Library
3677  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3678  * YUI licensed under the BSD License:
3679  * http://developer.yahoo.net/yui/license.txt
3680  * <script type="text/javascript">
3681  *
3682  */
3683 Roo.lib.Bezier = new function() {
3684
3685         this.getPosition = function(points, t) {
3686             var n = points.length;
3687             var tmp = [];
3688
3689             for (var i = 0; i < n; ++i) {
3690                 tmp[i] = [points[i][0], points[i][1]];
3691             }
3692
3693             for (var j = 1; j < n; ++j) {
3694                 for (i = 0; i < n - j; ++i) {
3695                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3696                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3697                 }
3698             }
3699
3700             return [ tmp[0][0], tmp[0][1] ];
3701
3702         };
3703     }; 
3704
3705 /**
3706  * @class Roo.lib.Color
3707  * @constructor
3708  * An abstract Color implementation. Concrete Color implementations should use
3709  * an instance of this function as their prototype, and implement the getRGB and
3710  * getHSL functions. getRGB should return an object representing the RGB
3711  * components of this Color, with the red, green, and blue components in the
3712  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3713  * return an object representing the HSL components of this Color, with the hue
3714  * component in the range [0,360), the saturation and lightness components in
3715  * the range [0,100], and the alpha component in the range [0,1].
3716  *
3717  *
3718  * Color.js
3719  *
3720  * Functions for Color handling and processing.
3721  *
3722  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3723  *
3724  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3725  * rights to this program, with the intention of it becoming part of the public
3726  * domain. Because this program is released into the public domain, it comes with
3727  * no warranty either expressed or implied, to the extent permitted by law.
3728  * 
3729  * For more free and public domain JavaScript code by the same author, visit:
3730  * http://www.safalra.com/web-design/javascript/
3731  * 
3732  */
3733 Roo.lib.Color = function() { }
3734
3735
3736 Roo.apply(Roo.lib.Color.prototype, {
3737   
3738   rgb : null,
3739   hsv : null,
3740   hsl : null,
3741   
3742   /**
3743    * getIntegerRGB
3744    * @return {Object} an object representing the RGBA components of this Color. The red,
3745    * green, and blue components are converted to integers in the range [0,255].
3746    * The alpha is a value in the range [0,1].
3747    */
3748   getIntegerRGB : function(){
3749
3750     // get the RGB components of this Color
3751     var rgb = this.getRGB();
3752
3753     // return the integer components
3754     return {
3755       'r' : Math.round(rgb.r),
3756       'g' : Math.round(rgb.g),
3757       'b' : Math.round(rgb.b),
3758       'a' : rgb.a
3759     };
3760
3761   },
3762
3763   /**
3764    * getPercentageRGB
3765    * @return {Object} an object representing the RGBA components of this Color. The red,
3766    * green, and blue components are converted to numbers in the range [0,100].
3767    * The alpha is a value in the range [0,1].
3768    */
3769   getPercentageRGB : function(){
3770
3771     // get the RGB components of this Color
3772     var rgb = this.getRGB();
3773
3774     // return the percentage components
3775     return {
3776       'r' : 100 * rgb.r / 255,
3777       'g' : 100 * rgb.g / 255,
3778       'b' : 100 * rgb.b / 255,
3779       'a' : rgb.a
3780     };
3781
3782   },
3783
3784   /**
3785    * getCSSHexadecimalRGB
3786    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3787    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3788    * are two-digit hexadecimal numbers.
3789    */
3790   getCSSHexadecimalRGB : function()
3791   {
3792
3793     // get the integer RGB components
3794     var rgb = this.getIntegerRGB();
3795
3796     // determine the hexadecimal equivalents
3797     var r16 = rgb.r.toString(16);
3798     var g16 = rgb.g.toString(16);
3799     var b16 = rgb.b.toString(16);
3800
3801     // return the CSS RGB Color value
3802     return '#'
3803         + (r16.length == 2 ? r16 : '0' + r16)
3804         + (g16.length == 2 ? g16 : '0' + g16)
3805         + (b16.length == 2 ? b16 : '0' + b16);
3806
3807   },
3808
3809   /**
3810    * getCSSIntegerRGB
3811    * @return {String} a string representing this Color as a CSS integer RGB Color
3812    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3813    * are integers in the range [0,255].
3814    */
3815   getCSSIntegerRGB : function(){
3816
3817     // get the integer RGB components
3818     var rgb = this.getIntegerRGB();
3819
3820     // return the CSS RGB Color value
3821     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3822
3823   },
3824
3825   /**
3826    * getCSSIntegerRGBA
3827    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3828    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3829    * b are integers in the range [0,255] and a is in the range [0,1].
3830    */
3831   getCSSIntegerRGBA : function(){
3832
3833     // get the integer RGB components
3834     var rgb = this.getIntegerRGB();
3835
3836     // return the CSS integer RGBA Color value
3837     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3838
3839   },
3840
3841   /**
3842    * getCSSPercentageRGB
3843    * @return {String} a string representing this Color as a CSS percentage RGB Color
3844    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3845    * b are in the range [0,100].
3846    */
3847   getCSSPercentageRGB : function(){
3848
3849     // get the percentage RGB components
3850     var rgb = this.getPercentageRGB();
3851
3852     // return the CSS RGB Color value
3853     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3854
3855   },
3856
3857   /**
3858    * getCSSPercentageRGBA
3859    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3860    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3861    * and b are in the range [0,100] and a is in the range [0,1].
3862    */
3863   getCSSPercentageRGBA : function(){
3864
3865     // get the percentage RGB components
3866     var rgb = this.getPercentageRGB();
3867
3868     // return the CSS percentage RGBA Color value
3869     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3870
3871   },
3872
3873   /**
3874    * getCSSHSL
3875    * @return {String} a string representing this Color as a CSS HSL Color value - that
3876    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3877    * s and l are in the range [0,100].
3878    */
3879   getCSSHSL : function(){
3880
3881     // get the HSL components
3882     var hsl = this.getHSL();
3883
3884     // return the CSS HSL Color value
3885     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3886
3887   },
3888
3889   /**
3890    * getCSSHSLA
3891    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3892    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3893    * s and l are in the range [0,100], and a is in the range [0,1].
3894    */
3895   getCSSHSLA : function(){
3896
3897     // get the HSL components
3898     var hsl = this.getHSL();
3899
3900     // return the CSS HSL Color value
3901     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3902
3903   },
3904
3905   /**
3906    * Sets the Color of the specified node to this Color. This functions sets
3907    * the CSS 'color' property for the node. The parameter is:
3908    * 
3909    * @param {DomElement} node - the node whose Color should be set
3910    */
3911   setNodeColor : function(node){
3912
3913     // set the Color of the node
3914     node.style.color = this.getCSSHexadecimalRGB();
3915
3916   },
3917
3918   /**
3919    * Sets the background Color of the specified node to this Color. This
3920    * functions sets the CSS 'background-color' property for the node. The
3921    * parameter is:
3922    *
3923    * @param {DomElement} node - the node whose background Color should be set
3924    */
3925   setNodeBackgroundColor : function(node){
3926
3927     // set the background Color of the node
3928     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3929
3930   },
3931   // convert between formats..
3932   toRGB: function()
3933   {
3934     var r = this.getIntegerRGB();
3935     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3936     
3937   },
3938   toHSL : function()
3939   {
3940      var hsl = this.getHSL();
3941   // return the CSS HSL Color value
3942     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3943     
3944   },
3945   
3946   toHSV : function()
3947   {
3948     var rgb = this.toRGB();
3949     var hsv = rgb.getHSV();
3950    // return the CSS HSL Color value
3951     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3952     
3953   },
3954   
3955   // modify  v = 0 ... 1 (eg. 0.5)
3956   saturate : function(v)
3957   {
3958       var rgb = this.toRGB();
3959       var hsv = rgb.getHSV();
3960       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3961       
3962   
3963   },
3964   
3965    
3966   /**
3967    * getRGB
3968    * @return {Object} the RGB and alpha components of this Color as an object with r,
3969    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3970    * the range [0,1].
3971    */
3972   getRGB: function(){
3973    
3974     // return the RGB components
3975     return {
3976       'r' : this.rgb.r,
3977       'g' : this.rgb.g,
3978       'b' : this.rgb.b,
3979       'a' : this.alpha
3980     };
3981
3982   },
3983
3984   /**
3985    * getHSV
3986    * @return {Object} the HSV and alpha components of this Color as an object with h,
3987    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3988    * [0,100], and a is in the range [0,1].
3989    */
3990   getHSV : function()
3991   {
3992     
3993     // calculate the HSV components if necessary
3994     if (this.hsv == null) {
3995       this.calculateHSV();
3996     }
3997
3998     // return the HSV components
3999     return {
4000       'h' : this.hsv.h,
4001       's' : this.hsv.s,
4002       'v' : this.hsv.v,
4003       'a' : this.alpha
4004     };
4005
4006   },
4007
4008   /**
4009    * getHSL
4010    * @return {Object} the HSL and alpha components of this Color as an object with h,
4011    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4012    * [0,100], and a is in the range [0,1].
4013    */
4014   getHSL : function(){
4015     
4016      
4017     // calculate the HSV components if necessary
4018     if (this.hsl == null) { this.calculateHSL(); }
4019
4020     // return the HSL components
4021     return {
4022       'h' : this.hsl.h,
4023       's' : this.hsl.s,
4024       'l' : this.hsl.l,
4025       'a' : this.alpha
4026     };
4027
4028   }
4029   
4030
4031 });
4032
4033
4034 /**
4035  * @class Roo.lib.RGBColor
4036  * @extends Roo.lib.Color
4037  * Creates a Color specified in the RGB Color space, with an optional alpha
4038  * component. The parameters are:
4039  * @constructor
4040  * 
4041
4042  * @param {Number} r - the red component, clipped to the range [0,255]
4043  * @param {Number} g - the green component, clipped to the range [0,255]
4044  * @param {Number} b - the blue component, clipped to the range [0,255]
4045  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4046  *     optional and defaults to 1
4047  */
4048 Roo.lib.RGBColor = function (r, g, b, a){
4049
4050   // store the alpha component after clipping it if necessary
4051   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4052
4053   // store the RGB components after clipping them if necessary
4054   this.rgb =
4055       {
4056         'r' : Math.max(0, Math.min(255, r)),
4057         'g' : Math.max(0, Math.min(255, g)),
4058         'b' : Math.max(0, Math.min(255, b))
4059       };
4060
4061   // initialise the HSV and HSL components to null
4062   
4063
4064   /* 
4065    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4066    * range [0,360). The parameters are:
4067    *
4068    * maximum - the maximum of the RGB component values
4069    * range   - the range of the RGB component values
4070    */
4071    
4072
4073 }
4074 // this does an 'exteds'
4075 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4076
4077   
4078     getHue  : function(maximum, range)
4079     {
4080       var rgb = this.rgb;
4081        
4082       // check whether the range is zero
4083       if (range == 0){
4084   
4085         // set the hue to zero (any hue is acceptable as the Color is grey)
4086         var hue = 0;
4087   
4088       }else{
4089   
4090         // determine which of the components has the highest value and set the hue
4091         switch (maximum){
4092   
4093           // red has the highest value
4094           case rgb.r:
4095             var hue = (rgb.g - rgb.b) / range * 60;
4096             if (hue < 0) { hue += 360; }
4097             break;
4098   
4099           // green has the highest value
4100           case rgb.g:
4101             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4102             break;
4103   
4104           // blue has the highest value
4105           case rgb.b:
4106             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4107             break;
4108   
4109         }
4110   
4111       }
4112   
4113       // return the hue
4114       return hue;
4115   
4116     },
4117
4118   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4119    * be returned be the getHSV function.
4120    */
4121    calculateHSV : function(){
4122     var rgb = this.rgb;
4123     // get the maximum and range of the RGB component values
4124     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4125     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4126
4127     // store the HSV components
4128     this.hsv =
4129         {
4130           'h' : this.getHue(maximum, range),
4131           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4132           'v' : maximum / 2.55
4133         };
4134
4135   },
4136
4137   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4138    * be returned be the getHSL function.
4139    */
4140    calculateHSL : function(){
4141     var rgb = this.rgb;
4142     // get the maximum and range of the RGB component values
4143     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4144     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4145
4146     // determine the lightness in the range [0,1]
4147     var l = maximum / 255 - range / 510;
4148
4149     // store the HSL components
4150     this.hsl =
4151         {
4152           'h' : this.getHue(maximum, range),
4153           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4154           'l' : 100 * l
4155         };
4156
4157   }
4158
4159 });
4160
4161 /**
4162  * @class Roo.lib.HSVColor
4163  * @extends Roo.lib.Color
4164  * Creates a Color specified in the HSV Color space, with an optional alpha
4165  * component. The parameters are:
4166  * @constructor
4167  *
4168  * @param {Number} h - the hue component, wrapped to the range [0,360)
4169  * @param {Number} s - the saturation component, clipped to the range [0,100]
4170  * @param {Number} v - the value component, clipped to the range [0,100]
4171  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4172  *     optional and defaults to 1
4173  */
4174 Roo.lib.HSVColor = function (h, s, v, a){
4175
4176   // store the alpha component after clipping it if necessary
4177   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4178
4179   // store the HSV components after clipping or wrapping them if necessary
4180   this.hsv =
4181       {
4182         'h' : (h % 360 + 360) % 360,
4183         's' : Math.max(0, Math.min(100, s)),
4184         'v' : Math.max(0, Math.min(100, v))
4185       };
4186
4187   // initialise the RGB and HSL components to null
4188   this.rgb = null;
4189   this.hsl = null;
4190 }
4191
4192 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4193   /* Calculates and stores the RGB components of this HSVColor so that they can
4194    * be returned be the getRGB function.
4195    */
4196   calculateRGB: function ()
4197   {
4198     var hsv = this.hsv;
4199     // check whether the saturation is zero
4200     if (hsv.s == 0){
4201
4202       // set the Color to the appropriate shade of grey
4203       var r = hsv.v;
4204       var g = hsv.v;
4205       var b = hsv.v;
4206
4207     }else{
4208
4209       // set some temporary values
4210       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4211       var p  = hsv.v * (1 - hsv.s / 100);
4212       var q  = hsv.v * (1 - hsv.s / 100 * f);
4213       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4214
4215       // set the RGB Color components to their temporary values
4216       switch (Math.floor(hsv.h / 60)){
4217         case 0: var r = hsv.v; var g = t; var b = p; break;
4218         case 1: var r = q; var g = hsv.v; var b = p; break;
4219         case 2: var r = p; var g = hsv.v; var b = t; break;
4220         case 3: var r = p; var g = q; var b = hsv.v; break;
4221         case 4: var r = t; var g = p; var b = hsv.v; break;
4222         case 5: var r = hsv.v; var g = p; var b = q; break;
4223       }
4224
4225     }
4226
4227     // store the RGB components
4228     this.rgb =
4229         {
4230           'r' : r * 2.55,
4231           'g' : g * 2.55,
4232           'b' : b * 2.55
4233         };
4234
4235   },
4236
4237   /* Calculates and stores the HSL components of this HSVColor so that they can
4238    * be returned be the getHSL function.
4239    */
4240   calculateHSL : function (){
4241
4242     var hsv = this.hsv;
4243     // determine the lightness in the range [0,100]
4244     var l = (2 - hsv.s / 100) * hsv.v / 2;
4245
4246     // store the HSL components
4247     this.hsl =
4248         {
4249           'h' : hsv.h,
4250           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4251           'l' : l
4252         };
4253
4254     // correct a division-by-zero error
4255     if (isNaN(hsl.s)) { hsl.s = 0; }
4256
4257   } 
4258  
4259
4260 });
4261  
4262
4263 /**
4264  * @class Roo.lib.HSLColor
4265  * @extends Roo.lib.Color
4266  *
4267  * @constructor
4268  * Creates a Color specified in the HSL Color space, with an optional alpha
4269  * component. The parameters are:
4270  *
4271  * @param {Number} h - the hue component, wrapped to the range [0,360)
4272  * @param {Number} s - the saturation component, clipped to the range [0,100]
4273  * @param {Number} l - the lightness component, clipped to the range [0,100]
4274  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4275  *     optional and defaults to 1
4276  */
4277
4278 Roo.lib.HSLColor = function(h, s, l, a){
4279
4280   // store the alpha component after clipping it if necessary
4281   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4282
4283   // store the HSL components after clipping or wrapping them if necessary
4284   this.hsl =
4285       {
4286         'h' : (h % 360 + 360) % 360,
4287         's' : Math.max(0, Math.min(100, s)),
4288         'l' : Math.max(0, Math.min(100, l))
4289       };
4290
4291   // initialise the RGB and HSV components to null
4292 }
4293
4294 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4295
4296   /* Calculates and stores the RGB components of this HSLColor so that they can
4297    * be returned be the getRGB function.
4298    */
4299   calculateRGB: function (){
4300
4301     // check whether the saturation is zero
4302     if (this.hsl.s == 0){
4303
4304       // store the RGB components representing the appropriate shade of grey
4305       this.rgb =
4306           {
4307             'r' : this.hsl.l * 2.55,
4308             'g' : this.hsl.l * 2.55,
4309             'b' : this.hsl.l * 2.55
4310           };
4311
4312     }else{
4313
4314       // set some temporary values
4315       var p = this.hsl.l < 50
4316             ? this.hsl.l * (1 + hsl.s / 100)
4317             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4318       var q = 2 * hsl.l - p;
4319
4320       // initialise the RGB components
4321       this.rgb =
4322           {
4323             'r' : (h + 120) / 60 % 6,
4324             'g' : h / 60,
4325             'b' : (h + 240) / 60 % 6
4326           };
4327
4328       // loop over the RGB components
4329       for (var key in this.rgb){
4330
4331         // ensure that the property is not inherited from the root object
4332         if (this.rgb.hasOwnProperty(key)){
4333
4334           // set the component to its value in the range [0,100]
4335           if (this.rgb[key] < 1){
4336             this.rgb[key] = q + (p - q) * this.rgb[key];
4337           }else if (this.rgb[key] < 3){
4338             this.rgb[key] = p;
4339           }else if (this.rgb[key] < 4){
4340             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4341           }else{
4342             this.rgb[key] = q;
4343           }
4344
4345           // set the component to its value in the range [0,255]
4346           this.rgb[key] *= 2.55;
4347
4348         }
4349
4350       }
4351
4352     }
4353
4354   },
4355
4356   /* Calculates and stores the HSV components of this HSLColor so that they can
4357    * be returned be the getHSL function.
4358    */
4359    calculateHSV : function(){
4360
4361     // set a temporary value
4362     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4363
4364     // store the HSV components
4365     this.hsv =
4366         {
4367           'h' : this.hsl.h,
4368           's' : 200 * t / (this.hsl.l + t),
4369           'v' : t + this.hsl.l
4370         };
4371
4372     // correct a division-by-zero error
4373     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4374
4375   }
4376  
4377
4378 });
4379 /*
4380  * Portions of this file are based on pieces of Yahoo User Interface Library
4381  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4382  * YUI licensed under the BSD License:
4383  * http://developer.yahoo.net/yui/license.txt
4384  * <script type="text/javascript">
4385  *
4386  */
4387 (function() {
4388
4389     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4390         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4391     };
4392
4393     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4394
4395     var fly = Roo.lib.AnimBase.fly;
4396     var Y = Roo.lib;
4397     var superclass = Y.ColorAnim.superclass;
4398     var proto = Y.ColorAnim.prototype;
4399
4400     proto.toString = function() {
4401         var el = this.getEl();
4402         var id = el.id || el.tagName;
4403         return ("ColorAnim " + id);
4404     };
4405
4406     proto.patterns.color = /color$/i;
4407     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4408     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4409     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4410     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4411
4412
4413     proto.parseColor = function(s) {
4414         if (s.length == 3) {
4415             return s;
4416         }
4417
4418         var c = this.patterns.hex.exec(s);
4419         if (c && c.length == 4) {
4420             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4421         }
4422
4423         c = this.patterns.rgb.exec(s);
4424         if (c && c.length == 4) {
4425             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4426         }
4427
4428         c = this.patterns.hex3.exec(s);
4429         if (c && c.length == 4) {
4430             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4431         }
4432
4433         return null;
4434     };
4435     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4436     proto.getAttribute = function(attr) {
4437         var el = this.getEl();
4438         if (this.patterns.color.test(attr)) {
4439             var val = fly(el).getStyle(attr);
4440
4441             if (this.patterns.transparent.test(val)) {
4442                 var parent = el.parentNode;
4443                 val = fly(parent).getStyle(attr);
4444
4445                 while (parent && this.patterns.transparent.test(val)) {
4446                     parent = parent.parentNode;
4447                     val = fly(parent).getStyle(attr);
4448                     if (parent.tagName.toUpperCase() == 'HTML') {
4449                         val = '#fff';
4450                     }
4451                 }
4452             }
4453         } else {
4454             val = superclass.getAttribute.call(this, attr);
4455         }
4456
4457         return val;
4458     };
4459     proto.getAttribute = function(attr) {
4460         var el = this.getEl();
4461         if (this.patterns.color.test(attr)) {
4462             var val = fly(el).getStyle(attr);
4463
4464             if (this.patterns.transparent.test(val)) {
4465                 var parent = el.parentNode;
4466                 val = fly(parent).getStyle(attr);
4467
4468                 while (parent && this.patterns.transparent.test(val)) {
4469                     parent = parent.parentNode;
4470                     val = fly(parent).getStyle(attr);
4471                     if (parent.tagName.toUpperCase() == 'HTML') {
4472                         val = '#fff';
4473                     }
4474                 }
4475             }
4476         } else {
4477             val = superclass.getAttribute.call(this, attr);
4478         }
4479
4480         return val;
4481     };
4482
4483     proto.doMethod = function(attr, start, end) {
4484         var val;
4485
4486         if (this.patterns.color.test(attr)) {
4487             val = [];
4488             for (var i = 0, len = start.length; i < len; ++i) {
4489                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4490             }
4491
4492             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4493         }
4494         else {
4495             val = superclass.doMethod.call(this, attr, start, end);
4496         }
4497
4498         return val;
4499     };
4500
4501     proto.setRuntimeAttribute = function(attr) {
4502         superclass.setRuntimeAttribute.call(this, attr);
4503
4504         if (this.patterns.color.test(attr)) {
4505             var attributes = this.attributes;
4506             var start = this.parseColor(this.runtimeAttributes[attr].start);
4507             var end = this.parseColor(this.runtimeAttributes[attr].end);
4508
4509             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4510                 end = this.parseColor(attributes[attr].by);
4511
4512                 for (var i = 0, len = start.length; i < len; ++i) {
4513                     end[i] = start[i] + end[i];
4514                 }
4515             }
4516
4517             this.runtimeAttributes[attr].start = start;
4518             this.runtimeAttributes[attr].end = end;
4519         }
4520     };
4521 })();
4522
4523 /*
4524  * Portions of this file are based on pieces of Yahoo User Interface Library
4525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4526  * YUI licensed under the BSD License:
4527  * http://developer.yahoo.net/yui/license.txt
4528  * <script type="text/javascript">
4529  *
4530  */
4531 Roo.lib.Easing = {
4532
4533
4534     easeNone: function (t, b, c, d) {
4535         return c * t / d + b;
4536     },
4537
4538
4539     easeIn: function (t, b, c, d) {
4540         return c * (t /= d) * t + b;
4541     },
4542
4543
4544     easeOut: function (t, b, c, d) {
4545         return -c * (t /= d) * (t - 2) + b;
4546     },
4547
4548
4549     easeBoth: function (t, b, c, d) {
4550         if ((t /= d / 2) < 1) {
4551             return c / 2 * t * t + b;
4552         }
4553
4554         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4555     },
4556
4557
4558     easeInStrong: function (t, b, c, d) {
4559         return c * (t /= d) * t * t * t + b;
4560     },
4561
4562
4563     easeOutStrong: function (t, b, c, d) {
4564         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4565     },
4566
4567
4568     easeBothStrong: function (t, b, c, d) {
4569         if ((t /= d / 2) < 1) {
4570             return c / 2 * t * t * t * t + b;
4571         }
4572
4573         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4574     },
4575
4576
4577
4578     elasticIn: function (t, b, c, d, a, p) {
4579         if (t == 0) {
4580             return b;
4581         }
4582         if ((t /= d) == 1) {
4583             return b + c;
4584         }
4585         if (!p) {
4586             p = d * .3;
4587         }
4588
4589         if (!a || a < Math.abs(c)) {
4590             a = c;
4591             var s = p / 4;
4592         }
4593         else {
4594             var s = p / (2 * Math.PI) * Math.asin(c / a);
4595         }
4596
4597         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4598     },
4599
4600
4601     elasticOut: function (t, b, c, d, a, p) {
4602         if (t == 0) {
4603             return b;
4604         }
4605         if ((t /= d) == 1) {
4606             return b + c;
4607         }
4608         if (!p) {
4609             p = d * .3;
4610         }
4611
4612         if (!a || a < Math.abs(c)) {
4613             a = c;
4614             var s = p / 4;
4615         }
4616         else {
4617             var s = p / (2 * Math.PI) * Math.asin(c / a);
4618         }
4619
4620         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4621     },
4622
4623
4624     elasticBoth: function (t, b, c, d, a, p) {
4625         if (t == 0) {
4626             return b;
4627         }
4628
4629         if ((t /= d / 2) == 2) {
4630             return b + c;
4631         }
4632
4633         if (!p) {
4634             p = d * (.3 * 1.5);
4635         }
4636
4637         if (!a || a < Math.abs(c)) {
4638             a = c;
4639             var s = p / 4;
4640         }
4641         else {
4642             var s = p / (2 * Math.PI) * Math.asin(c / a);
4643         }
4644
4645         if (t < 1) {
4646             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4647                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4648         }
4649         return a * Math.pow(2, -10 * (t -= 1)) *
4650                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4651     },
4652
4653
4654
4655     backIn: function (t, b, c, d, s) {
4656         if (typeof s == 'undefined') {
4657             s = 1.70158;
4658         }
4659         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4660     },
4661
4662
4663     backOut: function (t, b, c, d, s) {
4664         if (typeof s == 'undefined') {
4665             s = 1.70158;
4666         }
4667         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4668     },
4669
4670
4671     backBoth: function (t, b, c, d, s) {
4672         if (typeof s == 'undefined') {
4673             s = 1.70158;
4674         }
4675
4676         if ((t /= d / 2 ) < 1) {
4677             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4678         }
4679         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4680     },
4681
4682
4683     bounceIn: function (t, b, c, d) {
4684         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4685     },
4686
4687
4688     bounceOut: function (t, b, c, d) {
4689         if ((t /= d) < (1 / 2.75)) {
4690             return c * (7.5625 * t * t) + b;
4691         } else if (t < (2 / 2.75)) {
4692             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4693         } else if (t < (2.5 / 2.75)) {
4694             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4695         }
4696         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4697     },
4698
4699
4700     bounceBoth: function (t, b, c, d) {
4701         if (t < d / 2) {
4702             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4703         }
4704         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4705     }
4706 };/*
4707  * Portions of this file are based on pieces of Yahoo User Interface Library
4708  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4709  * YUI licensed under the BSD License:
4710  * http://developer.yahoo.net/yui/license.txt
4711  * <script type="text/javascript">
4712  *
4713  */
4714     (function() {
4715         Roo.lib.Motion = function(el, attributes, duration, method) {
4716             if (el) {
4717                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4718             }
4719         };
4720
4721         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4722
4723
4724         var Y = Roo.lib;
4725         var superclass = Y.Motion.superclass;
4726         var proto = Y.Motion.prototype;
4727
4728         proto.toString = function() {
4729             var el = this.getEl();
4730             var id = el.id || el.tagName;
4731             return ("Motion " + id);
4732         };
4733
4734         proto.patterns.points = /^points$/i;
4735
4736         proto.setAttribute = function(attr, val, unit) {
4737             if (this.patterns.points.test(attr)) {
4738                 unit = unit || 'px';
4739                 superclass.setAttribute.call(this, 'left', val[0], unit);
4740                 superclass.setAttribute.call(this, 'top', val[1], unit);
4741             } else {
4742                 superclass.setAttribute.call(this, attr, val, unit);
4743             }
4744         };
4745
4746         proto.getAttribute = function(attr) {
4747             if (this.patterns.points.test(attr)) {
4748                 var val = [
4749                         superclass.getAttribute.call(this, 'left'),
4750                         superclass.getAttribute.call(this, 'top')
4751                         ];
4752             } else {
4753                 val = superclass.getAttribute.call(this, attr);
4754             }
4755
4756             return val;
4757         };
4758
4759         proto.doMethod = function(attr, start, end) {
4760             var val = null;
4761
4762             if (this.patterns.points.test(attr)) {
4763                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4764                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4765             } else {
4766                 val = superclass.doMethod.call(this, attr, start, end);
4767             }
4768             return val;
4769         };
4770
4771         proto.setRuntimeAttribute = function(attr) {
4772             if (this.patterns.points.test(attr)) {
4773                 var el = this.getEl();
4774                 var attributes = this.attributes;
4775                 var start;
4776                 var control = attributes['points']['control'] || [];
4777                 var end;
4778                 var i, len;
4779
4780                 if (control.length > 0 && !(control[0] instanceof Array)) {
4781                     control = [control];
4782                 } else {
4783                     var tmp = [];
4784                     for (i = 0,len = control.length; i < len; ++i) {
4785                         tmp[i] = control[i];
4786                     }
4787                     control = tmp;
4788                 }
4789
4790                 Roo.fly(el).position();
4791
4792                 if (isset(attributes['points']['from'])) {
4793                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4794                 }
4795                 else {
4796                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4797                 }
4798
4799                 start = this.getAttribute('points');
4800
4801
4802                 if (isset(attributes['points']['to'])) {
4803                     end = translateValues.call(this, attributes['points']['to'], start);
4804
4805                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4806                     for (i = 0,len = control.length; i < len; ++i) {
4807                         control[i] = translateValues.call(this, control[i], start);
4808                     }
4809
4810
4811                 } else if (isset(attributes['points']['by'])) {
4812                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4813
4814                     for (i = 0,len = control.length; i < len; ++i) {
4815                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4816                     }
4817                 }
4818
4819                 this.runtimeAttributes[attr] = [start];
4820
4821                 if (control.length > 0) {
4822                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4823                 }
4824
4825                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4826             }
4827             else {
4828                 superclass.setRuntimeAttribute.call(this, attr);
4829             }
4830         };
4831
4832         var translateValues = function(val, start) {
4833             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4834             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4835
4836             return val;
4837         };
4838
4839         var isset = function(prop) {
4840             return (typeof prop !== 'undefined');
4841         };
4842     })();
4843 /*
4844  * Portions of this file are based on pieces of Yahoo User Interface Library
4845  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4846  * YUI licensed under the BSD License:
4847  * http://developer.yahoo.net/yui/license.txt
4848  * <script type="text/javascript">
4849  *
4850  */
4851     (function() {
4852         Roo.lib.Scroll = function(el, attributes, duration, method) {
4853             if (el) {
4854                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4855             }
4856         };
4857
4858         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4859
4860
4861         var Y = Roo.lib;
4862         var superclass = Y.Scroll.superclass;
4863         var proto = Y.Scroll.prototype;
4864
4865         proto.toString = function() {
4866             var el = this.getEl();
4867             var id = el.id || el.tagName;
4868             return ("Scroll " + id);
4869         };
4870
4871         proto.doMethod = function(attr, start, end) {
4872             var val = null;
4873
4874             if (attr == 'scroll') {
4875                 val = [
4876                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4877                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4878                         ];
4879
4880             } else {
4881                 val = superclass.doMethod.call(this, attr, start, end);
4882             }
4883             return val;
4884         };
4885
4886         proto.getAttribute = function(attr) {
4887             var val = null;
4888             var el = this.getEl();
4889
4890             if (attr == 'scroll') {
4891                 val = [ el.scrollLeft, el.scrollTop ];
4892             } else {
4893                 val = superclass.getAttribute.call(this, attr);
4894             }
4895
4896             return val;
4897         };
4898
4899         proto.setAttribute = function(attr, val, unit) {
4900             var el = this.getEl();
4901
4902             if (attr == 'scroll') {
4903                 el.scrollLeft = val[0];
4904                 el.scrollTop = val[1];
4905             } else {
4906                 superclass.setAttribute.call(this, attr, val, unit);
4907             }
4908         };
4909     })();
4910 /**
4911  * Originally based of this code... - refactored for Roo...
4912  * https://github.com/aaalsaleh/undo-manager
4913  
4914  * undo-manager.js
4915  * @author  Abdulrahman Alsaleh 
4916  * @copyright 2015 Abdulrahman Alsaleh 
4917  * @license  MIT License (c) 
4918  *
4919  * Hackily modifyed by alan@roojs.com
4920  *
4921  *
4922  *  
4923  *
4924  *  TOTALLY UNTESTED...
4925  *
4926  *  Documentation to be done....
4927  */
4928  
4929
4930 /**
4931 * @class Roo.lib.UndoManager
4932 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4933 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4934
4935  * Usage:
4936  * <pre><code>
4937
4938
4939 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4940  
4941 </code></pre>
4942
4943 * For more information see this blog post with examples:
4944 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4945      - Create Elements using DOM, HTML fragments and Templates</a>. 
4946 * @constructor
4947 * @param {Number} limit how far back to go ... use 1000?
4948 * @param {Object} scope usually use document..
4949 */
4950
4951 Roo.lib.UndoManager = function (limit, undoScopeHost)
4952 {
4953     this.stack = [];
4954     this.limit = limit;
4955     this.scope = undoScopeHost;
4956     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4957     if (this.fireEvent) {
4958         this.bindEvents();
4959     }
4960     this.reset();
4961     
4962 };
4963         
4964 Roo.lib.UndoManager.prototype = {
4965     
4966     limit : false,
4967     stack : false,
4968     scope :  false,
4969     fireEvent : false,
4970     position : 0,
4971     length : 0,
4972     
4973     
4974      /**
4975      * To push and execute a transaction, the method undoManager.transact
4976      * must be called by passing a transaction object as the first argument, and a merge
4977      * flag as the second argument. A transaction object has the following properties:
4978      *
4979      * Usage:
4980 <pre><code>
4981 undoManager.transact({
4982     label: 'Typing',
4983     execute: function() { ... },
4984     undo: function() { ... },
4985     // redo same as execute
4986     redo: function() { this.execute(); }
4987 }, false);
4988
4989 // merge transaction
4990 undoManager.transact({
4991     label: 'Typing',
4992     execute: function() { ... },  // this will be run...
4993     undo: function() { ... }, // what to do when undo is run.
4994     // redo same as execute
4995     redo: function() { this.execute(); }
4996 }, true); 
4997 </code></pre> 
4998      *
4999      * 
5000      * @param {Object} transaction The transaction to add to the stack.
5001      * @return {String} The HTML fragment
5002      */
5003     
5004     
5005     transact : function (transaction, merge)
5006     {
5007         if (arguments.length < 2) {
5008             throw new TypeError('Not enough arguments to UndoManager.transact.');
5009         }
5010
5011         transaction.execute();
5012
5013         this.stack.splice(0, this.position);
5014         if (merge && this.length) {
5015             this.stack[0].push(transaction);
5016         } else {
5017             this.stack.unshift([transaction]);
5018         }
5019     
5020         this.position = 0;
5021
5022         if (this.limit && this.stack.length > this.limit) {
5023             this.length = this.stack.length = this.limit;
5024         } else {
5025             this.length = this.stack.length;
5026         }
5027
5028         if (this.fireEvent) {
5029             this.scope.dispatchEvent(
5030                 new CustomEvent('DOMTransaction', {
5031                     detail: {
5032                         transactions: this.stack[0].slice()
5033                     },
5034                     bubbles: true,
5035                     cancelable: false
5036                 })
5037             );
5038         }
5039         
5040         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5041       
5042         
5043     },
5044
5045     undo : function ()
5046     {
5047         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5048         
5049         if (this.position < this.length) {
5050             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5051                 this.stack[this.position][i].undo();
5052             }
5053             this.position++;
5054
5055             if (this.fireEvent) {
5056                 this.scope.dispatchEvent(
5057                     new CustomEvent('undo', {
5058                         detail: {
5059                             transactions: this.stack[this.position - 1].slice()
5060                         },
5061                         bubbles: true,
5062                         cancelable: false
5063                     })
5064                 );
5065             }
5066         }
5067     },
5068
5069     redo : function ()
5070     {
5071         if (this.position > 0) {
5072             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5073                 this.stack[this.position - 1][i].redo();
5074             }
5075             this.position--;
5076
5077             if (this.fireEvent) {
5078                 this.scope.dispatchEvent(
5079                     new CustomEvent('redo', {
5080                         detail: {
5081                             transactions: this.stack[this.position].slice()
5082                         },
5083                         bubbles: true,
5084                         cancelable: false
5085                     })
5086                 );
5087             }
5088         }
5089     },
5090
5091     item : function (index)
5092     {
5093         if (index >= 0 && index < this.length) {
5094             return this.stack[index].slice();
5095         }
5096         return null;
5097     },
5098
5099     clearUndo : function () {
5100         this.stack.length = this.length = this.position;
5101     },
5102
5103     clearRedo : function () {
5104         this.stack.splice(0, this.position);
5105         this.position = 0;
5106         this.length = this.stack.length;
5107     },
5108     /**
5109      * Reset the undo - probaly done on load to clear all history.
5110      */
5111     reset : function()
5112     {
5113         this.stack = [];
5114         this.position = 0;
5115         this.length = 0;
5116         this.current_html = this.scope.innerHTML;
5117         if (this.timer !== false) {
5118             clearTimeout(this.timer);
5119         }
5120         this.timer = false;
5121         this.merge = false;
5122         this.addEvent();
5123         
5124     },
5125     current_html : '',
5126     timer : false,
5127     merge : false,
5128     
5129     
5130     // this will handle the undo/redo on the element.?
5131     bindEvents : function()
5132     {
5133         var el  = this.scope;
5134         el.undoManager = this;
5135         
5136         
5137         this.scope.addEventListener('keydown', function(e) {
5138             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5139                 if (e.shiftKey) {
5140                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5141                 } else {
5142                     el.undoManager.undo(); // Ctrl/Command + Z
5143                 }
5144         
5145                 e.preventDefault();
5146             }
5147         });
5148         /// ignore keyup..
5149         this.scope.addEventListener('keyup', function(e) {
5150             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5151                 e.preventDefault();
5152             }
5153         });
5154         
5155         
5156         
5157         var t = this;
5158         
5159         el.addEventListener('input', function(e) {
5160             if(el.innerHTML == t.current_html) {
5161                 return;
5162             }
5163             // only record events every second.
5164             if (t.timer !== false) {
5165                clearTimeout(t.timer);
5166                t.timer = false;
5167             }
5168             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5169             
5170             t.addEvent(t.merge);
5171             t.merge = true; // ignore changes happening every second..
5172         });
5173         },
5174     /**
5175      * Manually add an event.
5176      * Normall called without arguements - and it will just get added to the stack.
5177      * 
5178      */
5179     
5180     addEvent : function(merge)
5181     {
5182         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5183         // not sure if this should clear the timer 
5184         merge = typeof(merge) == 'undefined' ? false : merge; 
5185         
5186         this.scope.undoManager.transact({
5187             scope : this.scope,
5188             oldHTML: this.current_html,
5189             newHTML: this.scope.innerHTML,
5190             // nothing to execute (content already changed when input is fired)
5191             execute: function() { },
5192             undo: function() {
5193                 this.scope.innerHTML = this.current_html = this.oldHTML;
5194             },
5195             redo: function() {
5196                 this.scope.innerHTML = this.current_html = this.newHTML;
5197             }
5198         }, false); //merge);
5199         
5200         this.merge = merge;
5201         
5202         this.current_html = this.scope.innerHTML;
5203     }
5204     
5205     
5206      
5207     
5208     
5209     
5210 };
5211 /**
5212  * @class Roo.lib.Range
5213  * @constructor
5214  * This is a toolkit, normally used to copy features into a Dom Range element
5215  * Roo.lib.Range.wrap(x);
5216  *
5217  *
5218  *
5219  */
5220 Roo.lib.Range = function() { };
5221
5222 /**
5223  * Wrap a Dom Range object, to give it new features...
5224  * @static
5225  * @param {Range} the range to wrap
5226  */
5227 Roo.lib.Range.wrap = function(r) {
5228     return Roo.apply(r, Roo.lib.Range.prototype);
5229 };
5230 /**
5231  * find a parent node eg. LI / OL
5232  * @param {string|Array} node name or array of nodenames
5233  * @return {DomElement|false}
5234  */
5235 Roo.apply(Roo.lib.Range.prototype,
5236 {
5237     
5238     closest : function(str)
5239     {
5240         if (typeof(str) != 'string') {
5241             // assume it's a array.
5242             for(var i = 0;i < str.length;i++) {
5243                 var r = this.closest(str[i]);
5244                 if (r !== false) {
5245                     return r;
5246                 }
5247                 
5248             }
5249             return false;
5250         }
5251         str = str.toLowerCase();
5252         var n = this.commonAncestorContainer; // might not be a node
5253         while (n.nodeType != 1) {
5254             n = n.parentNode;
5255         }
5256         
5257         if (n.nodeName.toLowerCase() == str ) {
5258             return n;
5259         }
5260         if (n.nodeName.toLowerCase() == 'body') {
5261             return false;
5262         }
5263             
5264         return n.closest(str) || false;
5265         
5266     },
5267     cloneRange : function()
5268     {
5269         return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5270     }
5271 });/**
5272  * @class Roo.lib.Selection
5273  * @constructor
5274  * This is a toolkit, normally used to copy features into a Dom Selection element
5275  * Roo.lib.Selection.wrap(x);
5276  *
5277  *
5278  *
5279  */
5280 Roo.lib.Selection = function() { };
5281
5282 /**
5283  * Wrap a Dom Range object, to give it new features...
5284  * @static
5285  * @param {Range} the range to wrap
5286  */
5287 Roo.lib.Selection.wrap = function(r, doc) {
5288     Roo.apply(r, Roo.lib.Selection.prototype);
5289     r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5290     return r;
5291 };
5292 /**
5293  * find a parent node eg. LI / OL
5294  * @param {string|Array} node name or array of nodenames
5295  * @return {DomElement|false}
5296  */
5297 Roo.apply(Roo.lib.Selection.prototype,
5298 {
5299     /**
5300      * the owner document
5301      */
5302     ownerDocument : false,
5303     
5304     getRangeAt : function(n)
5305     {
5306         return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5307     },
5308     
5309     /**
5310      * insert node at selection 
5311      * @param {DomElement|string} node
5312      * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5313      */
5314     insertNode: function(node, cursor)
5315     {
5316         if (typeof(node) == 'string') {
5317             node = this.ownerDocument.createElement(node);
5318             if (cursor == 'in') {
5319                 node.innerHTML = '&nbsp;';
5320             }
5321         }
5322         
5323         var range = this.getRangeAt(0);
5324         
5325         if (this.type != 'Caret') {
5326             range.deleteContents();
5327         }
5328         var sn = node.childNodes[0]; // select the contents.
5329
5330         
5331         
5332         range.insertNode(node);
5333         if (cursor == 'after') {
5334             node.insertAdjacentHTML('afterend', '&nbsp;');
5335             sn = node.nextSibling;
5336         }
5337         
5338         if (cursor == 'none') {
5339             return;
5340         }
5341         
5342         this.cursorText(sn);
5343     },
5344     
5345     cursorText : function(n)
5346     {
5347        
5348         //var range = this.getRangeAt(0);
5349         range = Roo.lib.Range.wrap(new Range());
5350         //range.selectNode(n);
5351         
5352         var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5353         range.setStart(n.parentNode,ix);
5354         range.setEnd(n.parentNode,ix+1);
5355         //range.collapse(false);
5356          
5357         this.removeAllRanges();
5358         this.addRange(range);
5359         
5360         Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5361     },
5362     cursorAfter : function(n)
5363     {
5364         if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
5365             n.insertAdjacentHTML('afterend', '&nbsp;');
5366         }
5367         this.cursorText (n.nextSibling);
5368     }
5369         
5370     
5371 });/*
5372  * Based on:
5373  * Ext JS Library 1.1.1
5374  * Copyright(c) 2006-2007, Ext JS, LLC.
5375  *
5376  * Originally Released Under LGPL - original licence link has changed is not relivant.
5377  *
5378  * Fork - LGPL
5379  * <script type="text/javascript">
5380  */
5381
5382
5383 // nasty IE9 hack - what a pile of crap that is..
5384
5385  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5386     Range.prototype.createContextualFragment = function (html) {
5387         var doc = window.document;
5388         var container = doc.createElement("div");
5389         container.innerHTML = html;
5390         var frag = doc.createDocumentFragment(), n;
5391         while ((n = container.firstChild)) {
5392             frag.appendChild(n);
5393         }
5394         return frag;
5395     };
5396 }
5397
5398 /**
5399  * @class Roo.DomHelper
5400  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5401  * 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>.
5402  * @static
5403  */
5404 Roo.DomHelper = function(){
5405     var tempTableEl = null;
5406     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5407     var tableRe = /^table|tbody|tr|td$/i;
5408     var xmlns = {};
5409     // build as innerHTML where available
5410     /** @ignore */
5411     var createHtml = function(o){
5412         if(typeof o == 'string'){
5413             return o;
5414         }
5415         var b = "";
5416         if(!o.tag){
5417             o.tag = "div";
5418         }
5419         b += "<" + o.tag;
5420         for(var attr in o){
5421             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5422             if(attr == "style"){
5423                 var s = o["style"];
5424                 if(typeof s == "function"){
5425                     s = s.call();
5426                 }
5427                 if(typeof s == "string"){
5428                     b += ' style="' + s + '"';
5429                 }else if(typeof s == "object"){
5430                     b += ' style="';
5431                     for(var key in s){
5432                         if(typeof s[key] != "function"){
5433                             b += key + ":" + s[key] + ";";
5434                         }
5435                     }
5436                     b += '"';
5437                 }
5438             }else{
5439                 if(attr == "cls"){
5440                     b += ' class="' + o["cls"] + '"';
5441                 }else if(attr == "htmlFor"){
5442                     b += ' for="' + o["htmlFor"] + '"';
5443                 }else{
5444                     b += " " + attr + '="' + o[attr] + '"';
5445                 }
5446             }
5447         }
5448         if(emptyTags.test(o.tag)){
5449             b += "/>";
5450         }else{
5451             b += ">";
5452             var cn = o.children || o.cn;
5453             if(cn){
5454                 //http://bugs.kde.org/show_bug.cgi?id=71506
5455                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5456                     for(var i = 0, len = cn.length; i < len; i++) {
5457                         b += createHtml(cn[i], b);
5458                     }
5459                 }else{
5460                     b += createHtml(cn, b);
5461                 }
5462             }
5463             if(o.html){
5464                 b += o.html;
5465             }
5466             b += "</" + o.tag + ">";
5467         }
5468         return b;
5469     };
5470
5471     // build as dom
5472     /** @ignore */
5473     var createDom = function(o, parentNode){
5474          
5475         // defininition craeted..
5476         var ns = false;
5477         if (o.ns && o.ns != 'html') {
5478                
5479             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5480                 xmlns[o.ns] = o.xmlns;
5481                 ns = o.xmlns;
5482             }
5483             if (typeof(xmlns[o.ns]) == 'undefined') {
5484                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5485             }
5486             ns = xmlns[o.ns];
5487         }
5488         
5489         
5490         if (typeof(o) == 'string') {
5491             return parentNode.appendChild(document.createTextNode(o));
5492         }
5493         o.tag = o.tag || div;
5494         if (o.ns && Roo.isIE) {
5495             ns = false;
5496             o.tag = o.ns + ':' + o.tag;
5497             
5498         }
5499         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5500         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5501         for(var attr in o){
5502             
5503             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5504                     attr == "style" || typeof o[attr] == "function") { continue; }
5505                     
5506             if(attr=="cls" && Roo.isIE){
5507                 el.className = o["cls"];
5508             }else{
5509                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5510                 else { 
5511                     el[attr] = o[attr];
5512                 }
5513             }
5514         }
5515         Roo.DomHelper.applyStyles(el, o.style);
5516         var cn = o.children || o.cn;
5517         if(cn){
5518             //http://bugs.kde.org/show_bug.cgi?id=71506
5519              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5520                 for(var i = 0, len = cn.length; i < len; i++) {
5521                     createDom(cn[i], el);
5522                 }
5523             }else{
5524                 createDom(cn, el);
5525             }
5526         }
5527         if(o.html){
5528             el.innerHTML = o.html;
5529         }
5530         if(parentNode){
5531            parentNode.appendChild(el);
5532         }
5533         return el;
5534     };
5535
5536     var ieTable = function(depth, s, h, e){
5537         tempTableEl.innerHTML = [s, h, e].join('');
5538         var i = -1, el = tempTableEl;
5539         while(++i < depth && el.firstChild){
5540             el = el.firstChild;
5541         }
5542         return el;
5543     };
5544
5545     // kill repeat to save bytes
5546     var ts = '<table>',
5547         te = '</table>',
5548         tbs = ts+'<tbody>',
5549         tbe = '</tbody>'+te,
5550         trs = tbs + '<tr>',
5551         tre = '</tr>'+tbe;
5552
5553     /**
5554      * @ignore
5555      * Nasty code for IE's broken table implementation
5556      */
5557     var insertIntoTable = function(tag, where, el, html){
5558         if(!tempTableEl){
5559             tempTableEl = document.createElement('div');
5560         }
5561         var node;
5562         var before = null;
5563         if(tag == 'td'){
5564             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5565                 return;
5566             }
5567             if(where == 'beforebegin'){
5568                 before = el;
5569                 el = el.parentNode;
5570             } else{
5571                 before = el.nextSibling;
5572                 el = el.parentNode;
5573             }
5574             node = ieTable(4, trs, html, tre);
5575         }
5576         else if(tag == 'tr'){
5577             if(where == 'beforebegin'){
5578                 before = el;
5579                 el = el.parentNode;
5580                 node = ieTable(3, tbs, html, tbe);
5581             } else if(where == 'afterend'){
5582                 before = el.nextSibling;
5583                 el = el.parentNode;
5584                 node = ieTable(3, tbs, html, tbe);
5585             } else{ // INTO a TR
5586                 if(where == 'afterbegin'){
5587                     before = el.firstChild;
5588                 }
5589                 node = ieTable(4, trs, html, tre);
5590             }
5591         } else if(tag == 'tbody'){
5592             if(where == 'beforebegin'){
5593                 before = el;
5594                 el = el.parentNode;
5595                 node = ieTable(2, ts, html, te);
5596             } else if(where == 'afterend'){
5597                 before = el.nextSibling;
5598                 el = el.parentNode;
5599                 node = ieTable(2, ts, html, te);
5600             } else{
5601                 if(where == 'afterbegin'){
5602                     before = el.firstChild;
5603                 }
5604                 node = ieTable(3, tbs, html, tbe);
5605             }
5606         } else{ // TABLE
5607             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5608                 return;
5609             }
5610             if(where == 'afterbegin'){
5611                 before = el.firstChild;
5612             }
5613             node = ieTable(2, ts, html, te);
5614         }
5615         el.insertBefore(node, before);
5616         return node;
5617     };
5618     
5619     // this is a bit like the react update code...
5620     // 
5621     
5622     var updateNode = function(from, to)
5623     {
5624         // should we handle non-standard elements?
5625         Roo.log(["UpdateNode" , from, to]);
5626         if (from.nodeType != to.nodeType) {
5627             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5628             from.parentNode.replaceChild(to, from);
5629         }
5630         
5631         if (from.nodeType == 3) {
5632             // assume it's text?!
5633             if (from.data == to.data) {
5634                 return;
5635             }
5636             from.data = to.data;
5637             return;
5638         }
5639         if (!from.parentNode) {
5640             // not sure why this is happening?
5641             return;
5642         }
5643         // assume 'to' doesnt have '1/3 nodetypes!
5644         // not sure why, by from, parent node might not exist?
5645         if (from.nodeType !=1 || from.tagName != to.tagName) {
5646             Roo.log(["ReplaceChild" , from, to ]);
5647             
5648             from.parentNode.replaceChild(to, from);
5649             return;
5650         }
5651         // compare attributes
5652         var ar = Array.from(from.attributes);
5653         for(var i = 0; i< ar.length;i++) {
5654             if (to.hasAttribute(ar[i].name)) {
5655                 continue;
5656             }
5657             if (ar[i].name == 'id') { // always keep ids?
5658                continue;
5659             }
5660             //if (ar[i].name == 'style') {
5661             //   throw "style removed?";
5662             //}
5663             Roo.log("removeAttribute" + ar[i].name);
5664             from.removeAttribute(ar[i].name);
5665         }
5666         ar = to.attributes;
5667         for(var i = 0; i< ar.length;i++) {
5668             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5669                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5670                 continue;
5671             }
5672             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5673             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5674         }
5675         // children
5676         var far = Array.from(from.childNodes);
5677         var tar = Array.from(to.childNodes);
5678         // if the lengths are different.. then it's probably a editable content change, rather than
5679         // a change of the block definition..
5680         
5681         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5682          /*if (from.innerHTML == to.innerHTML) {
5683             return;
5684         }
5685         if (far.length != tar.length) {
5686             from.innerHTML = to.innerHTML;
5687             return;
5688         }
5689         */
5690         
5691         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5692             if (i >= far.length) {
5693                 from.appendChild(tar[i]);
5694                 Roo.log(["add", tar[i]]);
5695                 
5696             } else if ( i  >= tar.length) {
5697                 from.removeChild(far[i]);
5698                 Roo.log(["remove", far[i]]);
5699             } else {
5700                 
5701                 updateNode(far[i], tar[i]);
5702             }    
5703         }
5704         
5705         
5706         
5707         
5708     };
5709     
5710     
5711
5712     return {
5713         /** True to force the use of DOM instead of html fragments @type Boolean */
5714         useDom : false,
5715     
5716         /**
5717          * Returns the markup for the passed Element(s) config
5718          * @param {Object} o The Dom object spec (and children)
5719          * @return {String}
5720          */
5721         markup : function(o){
5722             return createHtml(o);
5723         },
5724     
5725         /**
5726          * Applies a style specification to an element
5727          * @param {String/HTMLElement} el The element to apply styles to
5728          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5729          * a function which returns such a specification.
5730          */
5731         applyStyles : function(el, styles){
5732             if(styles){
5733                el = Roo.fly(el);
5734                if(typeof styles == "string"){
5735                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5736                    var matches;
5737                    while ((matches = re.exec(styles)) != null){
5738                        el.setStyle(matches[1], matches[2]);
5739                    }
5740                }else if (typeof styles == "object"){
5741                    for (var style in styles){
5742                       el.setStyle(style, styles[style]);
5743                    }
5744                }else if (typeof styles == "function"){
5745                     Roo.DomHelper.applyStyles(el, styles.call());
5746                }
5747             }
5748         },
5749     
5750         /**
5751          * Inserts an HTML fragment into the Dom
5752          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5753          * @param {HTMLElement} el The context element
5754          * @param {String} html The HTML fragmenet
5755          * @return {HTMLElement} The new node
5756          */
5757         insertHtml : function(where, el, html){
5758             where = where.toLowerCase();
5759             if(el.insertAdjacentHTML){
5760                 if(tableRe.test(el.tagName)){
5761                     var rs;
5762                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5763                         return rs;
5764                     }
5765                 }
5766                 switch(where){
5767                     case "beforebegin":
5768                         el.insertAdjacentHTML('BeforeBegin', html);
5769                         return el.previousSibling;
5770                     case "afterbegin":
5771                         el.insertAdjacentHTML('AfterBegin', html);
5772                         return el.firstChild;
5773                     case "beforeend":
5774                         el.insertAdjacentHTML('BeforeEnd', html);
5775                         return el.lastChild;
5776                     case "afterend":
5777                         el.insertAdjacentHTML('AfterEnd', html);
5778                         return el.nextSibling;
5779                 }
5780                 throw 'Illegal insertion point -> "' + where + '"';
5781             }
5782             var range = el.ownerDocument.createRange();
5783             var frag;
5784             switch(where){
5785                  case "beforebegin":
5786                     range.setStartBefore(el);
5787                     frag = range.createContextualFragment(html);
5788                     el.parentNode.insertBefore(frag, el);
5789                     return el.previousSibling;
5790                  case "afterbegin":
5791                     if(el.firstChild){
5792                         range.setStartBefore(el.firstChild);
5793                         frag = range.createContextualFragment(html);
5794                         el.insertBefore(frag, el.firstChild);
5795                         return el.firstChild;
5796                     }else{
5797                         el.innerHTML = html;
5798                         return el.firstChild;
5799                     }
5800                 case "beforeend":
5801                     if(el.lastChild){
5802                         range.setStartAfter(el.lastChild);
5803                         frag = range.createContextualFragment(html);
5804                         el.appendChild(frag);
5805                         return el.lastChild;
5806                     }else{
5807                         el.innerHTML = html;
5808                         return el.lastChild;
5809                     }
5810                 case "afterend":
5811                     range.setStartAfter(el);
5812                     frag = range.createContextualFragment(html);
5813                     el.parentNode.insertBefore(frag, el.nextSibling);
5814                     return el.nextSibling;
5815                 }
5816                 throw 'Illegal insertion point -> "' + where + '"';
5817         },
5818     
5819         /**
5820          * Creates new Dom element(s) and inserts them before el
5821          * @param {String/HTMLElement/Element} el The context element
5822          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5823          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5824          * @return {HTMLElement/Roo.Element} The new node
5825          */
5826         insertBefore : function(el, o, returnElement){
5827             return this.doInsert(el, o, returnElement, "beforeBegin");
5828         },
5829     
5830         /**
5831          * Creates new Dom element(s) and inserts them after el
5832          * @param {String/HTMLElement/Element} el The context element
5833          * @param {Object} o The Dom object spec (and children)
5834          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5835          * @return {HTMLElement/Roo.Element} The new node
5836          */
5837         insertAfter : function(el, o, returnElement){
5838             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5839         },
5840     
5841         /**
5842          * Creates new Dom element(s) and inserts them as the first child of el
5843          * @param {String/HTMLElement/Element} el The context element
5844          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5845          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5846          * @return {HTMLElement/Roo.Element} The new node
5847          */
5848         insertFirst : function(el, o, returnElement){
5849             return this.doInsert(el, o, returnElement, "afterBegin");
5850         },
5851     
5852         // private
5853         doInsert : function(el, o, returnElement, pos, sibling){
5854             el = Roo.getDom(el);
5855             var newNode;
5856             if(this.useDom || o.ns){
5857                 newNode = createDom(o, null);
5858                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5859             }else{
5860                 var html = createHtml(o);
5861                 newNode = this.insertHtml(pos, el, html);
5862             }
5863             return returnElement ? Roo.get(newNode, true) : newNode;
5864         },
5865     
5866         /**
5867          * Creates new Dom element(s) and appends them to el
5868          * @param {String/HTMLElement/Element} el The context element
5869          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5870          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5871          * @return {HTMLElement/Roo.Element} The new node
5872          */
5873         append : function(el, o, returnElement){
5874             el = Roo.getDom(el);
5875             var newNode;
5876             if(this.useDom || o.ns){
5877                 newNode = createDom(o, null);
5878                 el.appendChild(newNode);
5879             }else{
5880                 var html = createHtml(o);
5881                 newNode = this.insertHtml("beforeEnd", el, html);
5882             }
5883             return returnElement ? Roo.get(newNode, true) : newNode;
5884         },
5885     
5886         /**
5887          * Creates new Dom element(s) and overwrites the contents of el with them
5888          * @param {String/HTMLElement/Element} el The context element
5889          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5890          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5891          * @return {HTMLElement/Roo.Element} The new node
5892          */
5893         overwrite : function(el, o, returnElement)
5894         {
5895             el = Roo.getDom(el);
5896             if (o.ns) {
5897               
5898                 while (el.childNodes.length) {
5899                     el.removeChild(el.firstChild);
5900                 }
5901                 createDom(o, el);
5902             } else {
5903                 el.innerHTML = createHtml(o);   
5904             }
5905             
5906             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5907         },
5908     
5909         /**
5910          * Creates a new Roo.DomHelper.Template from the Dom object spec
5911          * @param {Object} o The Dom object spec (and children)
5912          * @return {Roo.DomHelper.Template} The new template
5913          */
5914         createTemplate : function(o){
5915             var html = createHtml(o);
5916             return new Roo.Template(html);
5917         },
5918          /**
5919          * Updates the first element with the spec from the o (replacing if necessary)
5920          * This iterates through the children, and updates attributes / children etc..
5921          * @param {String/HTMLElement/Element} el The context element
5922          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5923          */
5924         
5925         update : function(el, o)
5926         {
5927             updateNode(Roo.getDom(el), createDom(o));
5928             
5929         }
5930         
5931         
5932     };
5933 }();
5934 /*
5935  * Based on:
5936  * Ext JS Library 1.1.1
5937  * Copyright(c) 2006-2007, Ext JS, LLC.
5938  *
5939  * Originally Released Under LGPL - original licence link has changed is not relivant.
5940  *
5941  * Fork - LGPL
5942  * <script type="text/javascript">
5943  */
5944  
5945 /**
5946 * @class Roo.Template
5947 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5948 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5949 * Usage:
5950 <pre><code>
5951 var t = new Roo.Template({
5952     html :  '&lt;div name="{id}"&gt;' + 
5953         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5954         '&lt;/div&gt;',
5955     myformat: function (value, allValues) {
5956         return 'XX' + value;
5957     }
5958 });
5959 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5960 </code></pre>
5961 * For more information see this blog post with examples:
5962 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5963      - Create Elements using DOM, HTML fragments and Templates</a>. 
5964 * @constructor
5965 * @param {Object} cfg - Configuration object.
5966 */
5967 Roo.Template = function(cfg){
5968     // BC!
5969     if(cfg instanceof Array){
5970         cfg = cfg.join("");
5971     }else if(arguments.length > 1){
5972         cfg = Array.prototype.join.call(arguments, "");
5973     }
5974     
5975     
5976     if (typeof(cfg) == 'object') {
5977         Roo.apply(this,cfg)
5978     } else {
5979         // bc
5980         this.html = cfg;
5981     }
5982     if (this.url) {
5983         this.load();
5984     }
5985     
5986 };
5987 Roo.Template.prototype = {
5988     
5989     /**
5990      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5991      */
5992     onLoad : false,
5993     
5994     
5995     /**
5996      * @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..
5997      *                    it should be fixed so that template is observable...
5998      */
5999     url : false,
6000     /**
6001      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6002      */
6003     html : '',
6004     
6005     
6006     compiled : false,
6007     loaded : false,
6008     /**
6009      * Returns an HTML fragment of this template with the specified values applied.
6010      * @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'})
6011      * @return {String} The HTML fragment
6012      */
6013     
6014    
6015     
6016     applyTemplate : function(values){
6017         //Roo.log(["applyTemplate", values]);
6018         try {
6019            
6020             if(this.compiled){
6021                 return this.compiled(values);
6022             }
6023             var useF = this.disableFormats !== true;
6024             var fm = Roo.util.Format, tpl = this;
6025             var fn = function(m, name, format, args){
6026                 if(format && useF){
6027                     if(format.substr(0, 5) == "this."){
6028                         return tpl.call(format.substr(5), values[name], values);
6029                     }else{
6030                         if(args){
6031                             // quoted values are required for strings in compiled templates, 
6032                             // but for non compiled we need to strip them
6033                             // quoted reversed for jsmin
6034                             var re = /^\s*['"](.*)["']\s*$/;
6035                             args = args.split(',');
6036                             for(var i = 0, len = args.length; i < len; i++){
6037                                 args[i] = args[i].replace(re, "$1");
6038                             }
6039                             args = [values[name]].concat(args);
6040                         }else{
6041                             args = [values[name]];
6042                         }
6043                         return fm[format].apply(fm, args);
6044                     }
6045                 }else{
6046                     return values[name] !== undefined ? values[name] : "";
6047                 }
6048             };
6049             return this.html.replace(this.re, fn);
6050         } catch (e) {
6051             Roo.log(e);
6052             throw e;
6053         }
6054          
6055     },
6056     
6057     loading : false,
6058       
6059     load : function ()
6060     {
6061          
6062         if (this.loading) {
6063             return;
6064         }
6065         var _t = this;
6066         
6067         this.loading = true;
6068         this.compiled = false;
6069         
6070         var cx = new Roo.data.Connection();
6071         cx.request({
6072             url : this.url,
6073             method : 'GET',
6074             success : function (response) {
6075                 _t.loading = false;
6076                 _t.url = false;
6077                 
6078                 _t.set(response.responseText,true);
6079                 _t.loaded = true;
6080                 if (_t.onLoad) {
6081                     _t.onLoad();
6082                 }
6083              },
6084             failure : function(response) {
6085                 Roo.log("Template failed to load from " + _t.url);
6086                 _t.loading = false;
6087             }
6088         });
6089     },
6090
6091     /**
6092      * Sets the HTML used as the template and optionally compiles it.
6093      * @param {String} html
6094      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6095      * @return {Roo.Template} this
6096      */
6097     set : function(html, compile){
6098         this.html = html;
6099         this.compiled = false;
6100         if(compile){
6101             this.compile();
6102         }
6103         return this;
6104     },
6105     
6106     /**
6107      * True to disable format functions (defaults to false)
6108      * @type Boolean
6109      */
6110     disableFormats : false,
6111     
6112     /**
6113     * The regular expression used to match template variables 
6114     * @type RegExp
6115     * @property 
6116     */
6117     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6118     
6119     /**
6120      * Compiles the template into an internal function, eliminating the RegEx overhead.
6121      * @return {Roo.Template} this
6122      */
6123     compile : function(){
6124         var fm = Roo.util.Format;
6125         var useF = this.disableFormats !== true;
6126         var sep = Roo.isGecko ? "+" : ",";
6127         var fn = function(m, name, format, args){
6128             if(format && useF){
6129                 args = args ? ',' + args : "";
6130                 if(format.substr(0, 5) != "this."){
6131                     format = "fm." + format + '(';
6132                 }else{
6133                     format = 'this.call("'+ format.substr(5) + '", ';
6134                     args = ", values";
6135                 }
6136             }else{
6137                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6138             }
6139             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6140         };
6141         var body;
6142         // branched to use + in gecko and [].join() in others
6143         if(Roo.isGecko){
6144             body = "this.compiled = function(values){ return '" +
6145                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6146                     "';};";
6147         }else{
6148             body = ["this.compiled = function(values){ return ['"];
6149             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6150             body.push("'].join('');};");
6151             body = body.join('');
6152         }
6153         /**
6154          * eval:var:values
6155          * eval:var:fm
6156          */
6157         eval(body);
6158         return this;
6159     },
6160     
6161     // private function used to call members
6162     call : function(fnName, value, allValues){
6163         return this[fnName](value, allValues);
6164     },
6165     
6166     /**
6167      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6168      * @param {String/HTMLElement/Roo.Element} el The context element
6169      * @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'})
6170      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6171      * @return {HTMLElement/Roo.Element} The new node or Element
6172      */
6173     insertFirst: function(el, values, returnElement){
6174         return this.doInsert('afterBegin', el, values, returnElement);
6175     },
6176
6177     /**
6178      * Applies the supplied values to the template and inserts the new node(s) before el.
6179      * @param {String/HTMLElement/Roo.Element} el The context element
6180      * @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'})
6181      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6182      * @return {HTMLElement/Roo.Element} The new node or Element
6183      */
6184     insertBefore: function(el, values, returnElement){
6185         return this.doInsert('beforeBegin', el, values, returnElement);
6186     },
6187
6188     /**
6189      * Applies the supplied values to the template and inserts the new node(s) after el.
6190      * @param {String/HTMLElement/Roo.Element} el The context element
6191      * @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'})
6192      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6193      * @return {HTMLElement/Roo.Element} The new node or Element
6194      */
6195     insertAfter : function(el, values, returnElement){
6196         return this.doInsert('afterEnd', el, values, returnElement);
6197     },
6198     
6199     /**
6200      * Applies the supplied values to the template and appends the new node(s) to el.
6201      * @param {String/HTMLElement/Roo.Element} el The context element
6202      * @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'})
6203      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6204      * @return {HTMLElement/Roo.Element} The new node or Element
6205      */
6206     append : function(el, values, returnElement){
6207         return this.doInsert('beforeEnd', el, values, returnElement);
6208     },
6209
6210     doInsert : function(where, el, values, returnEl){
6211         el = Roo.getDom(el);
6212         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6213         return returnEl ? Roo.get(newNode, true) : newNode;
6214     },
6215
6216     /**
6217      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6218      * @param {String/HTMLElement/Roo.Element} el The context element
6219      * @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'})
6220      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6221      * @return {HTMLElement/Roo.Element} The new node or Element
6222      */
6223     overwrite : function(el, values, returnElement){
6224         el = Roo.getDom(el);
6225         el.innerHTML = this.applyTemplate(values);
6226         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6227     }
6228 };
6229 /**
6230  * Alias for {@link #applyTemplate}
6231  * @method
6232  */
6233 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6234
6235 // backwards compat
6236 Roo.DomHelper.Template = Roo.Template;
6237
6238 /**
6239  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6240  * @param {String/HTMLElement} el A DOM element or its id
6241  * @returns {Roo.Template} The created template
6242  * @static
6243  */
6244 Roo.Template.from = function(el){
6245     el = Roo.getDom(el);
6246     return new Roo.Template(el.value || el.innerHTML);
6247 };/*
6248  * Based on:
6249  * Ext JS Library 1.1.1
6250  * Copyright(c) 2006-2007, Ext JS, LLC.
6251  *
6252  * Originally Released Under LGPL - original licence link has changed is not relivant.
6253  *
6254  * Fork - LGPL
6255  * <script type="text/javascript">
6256  */
6257  
6258
6259 /*
6260  * This is code is also distributed under MIT license for use
6261  * with jQuery and prototype JavaScript libraries.
6262  */
6263 /**
6264  * @class Roo.DomQuery
6265 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).
6266 <p>
6267 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>
6268
6269 <p>
6270 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.
6271 </p>
6272 <h4>Element Selectors:</h4>
6273 <ul class="list">
6274     <li> <b>*</b> any element</li>
6275     <li> <b>E</b> an element with the tag E</li>
6276     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6277     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6278     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6279     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6280 </ul>
6281 <h4>Attribute Selectors:</h4>
6282 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6283 <ul class="list">
6284     <li> <b>E[foo]</b> has an attribute "foo"</li>
6285     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6286     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6287     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6288     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6289     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6290     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6291 </ul>
6292 <h4>Pseudo Classes:</h4>
6293 <ul class="list">
6294     <li> <b>E:first-child</b> E is the first child of its parent</li>
6295     <li> <b>E:last-child</b> E is the last child of its parent</li>
6296     <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>
6297     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6298     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6299     <li> <b>E:only-child</b> E is the only child of its parent</li>
6300     <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>
6301     <li> <b>E:first</b> the first E in the resultset</li>
6302     <li> <b>E:last</b> the last E in the resultset</li>
6303     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6304     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6305     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6306     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6307     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6308     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6309     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6310     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6311     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6312 </ul>
6313 <h4>CSS Value Selectors:</h4>
6314 <ul class="list">
6315     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6316     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6317     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6318     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6319     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6320     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6321 </ul>
6322  * @static
6323  */
6324 Roo.DomQuery = function(){
6325     var cache = {}, simpleCache = {}, valueCache = {};
6326     var nonSpace = /\S/;
6327     var trimRe = /^\s+|\s+$/g;
6328     var tplRe = /\{(\d+)\}/g;
6329     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6330     var tagTokenRe = /^(#)?([\w-\*]+)/;
6331     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6332
6333     function child(p, index){
6334         var i = 0;
6335         var n = p.firstChild;
6336         while(n){
6337             if(n.nodeType == 1){
6338                if(++i == index){
6339                    return n;
6340                }
6341             }
6342             n = n.nextSibling;
6343         }
6344         return null;
6345     };
6346
6347     function next(n){
6348         while((n = n.nextSibling) && n.nodeType != 1);
6349         return n;
6350     };
6351
6352     function prev(n){
6353         while((n = n.previousSibling) && n.nodeType != 1);
6354         return n;
6355     };
6356
6357     function children(d){
6358         var n = d.firstChild, ni = -1;
6359             while(n){
6360                 var nx = n.nextSibling;
6361                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6362                     d.removeChild(n);
6363                 }else{
6364                     n.nodeIndex = ++ni;
6365                 }
6366                 n = nx;
6367             }
6368             return this;
6369         };
6370
6371     function byClassName(c, a, v){
6372         if(!v){
6373             return c;
6374         }
6375         var r = [], ri = -1, cn;
6376         for(var i = 0, ci; ci = c[i]; i++){
6377             
6378             
6379             if((' '+
6380                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6381                  +' ').indexOf(v) != -1){
6382                 r[++ri] = ci;
6383             }
6384         }
6385         return r;
6386     };
6387
6388     function attrValue(n, attr){
6389         if(!n.tagName && typeof n.length != "undefined"){
6390             n = n[0];
6391         }
6392         if(!n){
6393             return null;
6394         }
6395         if(attr == "for"){
6396             return n.htmlFor;
6397         }
6398         if(attr == "class" || attr == "className"){
6399             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6400         }
6401         return n.getAttribute(attr) || n[attr];
6402
6403     };
6404
6405     function getNodes(ns, mode, tagName){
6406         var result = [], ri = -1, cs;
6407         if(!ns){
6408             return result;
6409         }
6410         tagName = tagName || "*";
6411         if(typeof ns.getElementsByTagName != "undefined"){
6412             ns = [ns];
6413         }
6414         if(!mode){
6415             for(var i = 0, ni; ni = ns[i]; i++){
6416                 cs = ni.getElementsByTagName(tagName);
6417                 for(var j = 0, ci; ci = cs[j]; j++){
6418                     result[++ri] = ci;
6419                 }
6420             }
6421         }else if(mode == "/" || mode == ">"){
6422             var utag = tagName.toUpperCase();
6423             for(var i = 0, ni, cn; ni = ns[i]; i++){
6424                 cn = ni.children || ni.childNodes;
6425                 for(var j = 0, cj; cj = cn[j]; j++){
6426                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6427                         result[++ri] = cj;
6428                     }
6429                 }
6430             }
6431         }else if(mode == "+"){
6432             var utag = tagName.toUpperCase();
6433             for(var i = 0, n; n = ns[i]; i++){
6434                 while((n = n.nextSibling) && n.nodeType != 1);
6435                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6436                     result[++ri] = n;
6437                 }
6438             }
6439         }else if(mode == "~"){
6440             for(var i = 0, n; n = ns[i]; i++){
6441                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6442                 if(n){
6443                     result[++ri] = n;
6444                 }
6445             }
6446         }
6447         return result;
6448     };
6449
6450     function concat(a, b){
6451         if(b.slice){
6452             return a.concat(b);
6453         }
6454         for(var i = 0, l = b.length; i < l; i++){
6455             a[a.length] = b[i];
6456         }
6457         return a;
6458     }
6459
6460     function byTag(cs, tagName){
6461         if(cs.tagName || cs == document){
6462             cs = [cs];
6463         }
6464         if(!tagName){
6465             return cs;
6466         }
6467         var r = [], ri = -1;
6468         tagName = tagName.toLowerCase();
6469         for(var i = 0, ci; ci = cs[i]; i++){
6470             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6471                 r[++ri] = ci;
6472             }
6473         }
6474         return r;
6475     };
6476
6477     function byId(cs, attr, id){
6478         if(cs.tagName || cs == document){
6479             cs = [cs];
6480         }
6481         if(!id){
6482             return cs;
6483         }
6484         var r = [], ri = -1;
6485         for(var i = 0,ci; ci = cs[i]; i++){
6486             if(ci && ci.id == id){
6487                 r[++ri] = ci;
6488                 return r;
6489             }
6490         }
6491         return r;
6492     };
6493
6494     function byAttribute(cs, attr, value, op, custom){
6495         var r = [], ri = -1, st = custom=="{";
6496         var f = Roo.DomQuery.operators[op];
6497         for(var i = 0, ci; ci = cs[i]; i++){
6498             var a;
6499             if(st){
6500                 a = Roo.DomQuery.getStyle(ci, attr);
6501             }
6502             else if(attr == "class" || attr == "className"){
6503                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6504             }else if(attr == "for"){
6505                 a = ci.htmlFor;
6506             }else if(attr == "href"){
6507                 a = ci.getAttribute("href", 2);
6508             }else{
6509                 a = ci.getAttribute(attr);
6510             }
6511             if((f && f(a, value)) || (!f && a)){
6512                 r[++ri] = ci;
6513             }
6514         }
6515         return r;
6516     };
6517
6518     function byPseudo(cs, name, value){
6519         return Roo.DomQuery.pseudos[name](cs, value);
6520     };
6521
6522     // This is for IE MSXML which does not support expandos.
6523     // IE runs the same speed using setAttribute, however FF slows way down
6524     // and Safari completely fails so they need to continue to use expandos.
6525     var isIE = window.ActiveXObject ? true : false;
6526
6527     // this eval is stop the compressor from
6528     // renaming the variable to something shorter
6529     
6530     /** eval:var:batch */
6531     var batch = 30803; 
6532
6533     var key = 30803;
6534
6535     function nodupIEXml(cs){
6536         var d = ++key;
6537         cs[0].setAttribute("_nodup", d);
6538         var r = [cs[0]];
6539         for(var i = 1, len = cs.length; i < len; i++){
6540             var c = cs[i];
6541             if(!c.getAttribute("_nodup") != d){
6542                 c.setAttribute("_nodup", d);
6543                 r[r.length] = c;
6544             }
6545         }
6546         for(var i = 0, len = cs.length; i < len; i++){
6547             cs[i].removeAttribute("_nodup");
6548         }
6549         return r;
6550     }
6551
6552     function nodup(cs){
6553         if(!cs){
6554             return [];
6555         }
6556         var len = cs.length, c, i, r = cs, cj, ri = -1;
6557         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6558             return cs;
6559         }
6560         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6561             return nodupIEXml(cs);
6562         }
6563         var d = ++key;
6564         cs[0]._nodup = d;
6565         for(i = 1; c = cs[i]; i++){
6566             if(c._nodup != d){
6567                 c._nodup = d;
6568             }else{
6569                 r = [];
6570                 for(var j = 0; j < i; j++){
6571                     r[++ri] = cs[j];
6572                 }
6573                 for(j = i+1; cj = cs[j]; j++){
6574                     if(cj._nodup != d){
6575                         cj._nodup = d;
6576                         r[++ri] = cj;
6577                     }
6578                 }
6579                 return r;
6580             }
6581         }
6582         return r;
6583     }
6584
6585     function quickDiffIEXml(c1, c2){
6586         var d = ++key;
6587         for(var i = 0, len = c1.length; i < len; i++){
6588             c1[i].setAttribute("_qdiff", d);
6589         }
6590         var r = [];
6591         for(var i = 0, len = c2.length; i < len; i++){
6592             if(c2[i].getAttribute("_qdiff") != d){
6593                 r[r.length] = c2[i];
6594             }
6595         }
6596         for(var i = 0, len = c1.length; i < len; i++){
6597            c1[i].removeAttribute("_qdiff");
6598         }
6599         return r;
6600     }
6601
6602     function quickDiff(c1, c2){
6603         var len1 = c1.length;
6604         if(!len1){
6605             return c2;
6606         }
6607         if(isIE && c1[0].selectSingleNode){
6608             return quickDiffIEXml(c1, c2);
6609         }
6610         var d = ++key;
6611         for(var i = 0; i < len1; i++){
6612             c1[i]._qdiff = d;
6613         }
6614         var r = [];
6615         for(var i = 0, len = c2.length; i < len; i++){
6616             if(c2[i]._qdiff != d){
6617                 r[r.length] = c2[i];
6618             }
6619         }
6620         return r;
6621     }
6622
6623     function quickId(ns, mode, root, id){
6624         if(ns == root){
6625            var d = root.ownerDocument || root;
6626            return d.getElementById(id);
6627         }
6628         ns = getNodes(ns, mode, "*");
6629         return byId(ns, null, id);
6630     }
6631
6632     return {
6633         getStyle : function(el, name){
6634             return Roo.fly(el).getStyle(name);
6635         },
6636         /**
6637          * Compiles a selector/xpath query into a reusable function. The returned function
6638          * takes one parameter "root" (optional), which is the context node from where the query should start.
6639          * @param {String} selector The selector/xpath query
6640          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6641          * @return {Function}
6642          */
6643         compile : function(path, type){
6644             type = type || "select";
6645             
6646             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6647             var q = path, mode, lq;
6648             var tk = Roo.DomQuery.matchers;
6649             var tklen = tk.length;
6650             var mm;
6651
6652             // accept leading mode switch
6653             var lmode = q.match(modeRe);
6654             if(lmode && lmode[1]){
6655                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6656                 q = q.replace(lmode[1], "");
6657             }
6658             // strip leading slashes
6659             while(path.substr(0, 1)=="/"){
6660                 path = path.substr(1);
6661             }
6662
6663             while(q && lq != q){
6664                 lq = q;
6665                 var tm = q.match(tagTokenRe);
6666                 if(type == "select"){
6667                     if(tm){
6668                         if(tm[1] == "#"){
6669                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6670                         }else{
6671                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6672                         }
6673                         q = q.replace(tm[0], "");
6674                     }else if(q.substr(0, 1) != '@'){
6675                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6676                     }
6677                 }else{
6678                     if(tm){
6679                         if(tm[1] == "#"){
6680                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6681                         }else{
6682                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6683                         }
6684                         q = q.replace(tm[0], "");
6685                     }
6686                 }
6687                 while(!(mm = q.match(modeRe))){
6688                     var matched = false;
6689                     for(var j = 0; j < tklen; j++){
6690                         var t = tk[j];
6691                         var m = q.match(t.re);
6692                         if(m){
6693                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6694                                                     return m[i];
6695                                                 });
6696                             q = q.replace(m[0], "");
6697                             matched = true;
6698                             break;
6699                         }
6700                     }
6701                     // prevent infinite loop on bad selector
6702                     if(!matched){
6703                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6704                     }
6705                 }
6706                 if(mm[1]){
6707                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6708                     q = q.replace(mm[1], "");
6709                 }
6710             }
6711             fn[fn.length] = "return nodup(n);\n}";
6712             
6713              /** 
6714               * list of variables that need from compression as they are used by eval.
6715              *  eval:var:batch 
6716              *  eval:var:nodup
6717              *  eval:var:byTag
6718              *  eval:var:ById
6719              *  eval:var:getNodes
6720              *  eval:var:quickId
6721              *  eval:var:mode
6722              *  eval:var:root
6723              *  eval:var:n
6724              *  eval:var:byClassName
6725              *  eval:var:byPseudo
6726              *  eval:var:byAttribute
6727              *  eval:var:attrValue
6728              * 
6729              **/ 
6730             eval(fn.join(""));
6731             return f;
6732         },
6733
6734         /**
6735          * Selects a group of elements.
6736          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6737          * @param {Node} root (optional) The start of the query (defaults to document).
6738          * @return {Array}
6739          */
6740         select : function(path, root, type){
6741             if(!root || root == document){
6742                 root = document;
6743             }
6744             if(typeof root == "string"){
6745                 root = document.getElementById(root);
6746             }
6747             var paths = path.split(",");
6748             var results = [];
6749             for(var i = 0, len = paths.length; i < len; i++){
6750                 var p = paths[i].replace(trimRe, "");
6751                 if(!cache[p]){
6752                     cache[p] = Roo.DomQuery.compile(p);
6753                     if(!cache[p]){
6754                         throw p + " is not a valid selector";
6755                     }
6756                 }
6757                 var result = cache[p](root);
6758                 if(result && result != document){
6759                     results = results.concat(result);
6760                 }
6761             }
6762             if(paths.length > 1){
6763                 return nodup(results);
6764             }
6765             return results;
6766         },
6767
6768         /**
6769          * Selects a single element.
6770          * @param {String} selector The selector/xpath query
6771          * @param {Node} root (optional) The start of the query (defaults to document).
6772          * @return {Element}
6773          */
6774         selectNode : function(path, root){
6775             return Roo.DomQuery.select(path, root)[0];
6776         },
6777
6778         /**
6779          * Selects the value of a node, optionally replacing null with the defaultValue.
6780          * @param {String} selector The selector/xpath query
6781          * @param {Node} root (optional) The start of the query (defaults to document).
6782          * @param {String} defaultValue
6783          */
6784         selectValue : function(path, root, defaultValue){
6785             path = path.replace(trimRe, "");
6786             if(!valueCache[path]){
6787                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6788             }
6789             var n = valueCache[path](root);
6790             n = n[0] ? n[0] : n;
6791             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6792             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6793         },
6794
6795         /**
6796          * Selects the value of a node, parsing integers and floats.
6797          * @param {String} selector The selector/xpath query
6798          * @param {Node} root (optional) The start of the query (defaults to document).
6799          * @param {Number} defaultValue
6800          * @return {Number}
6801          */
6802         selectNumber : function(path, root, defaultValue){
6803             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6804             return parseFloat(v);
6805         },
6806
6807         /**
6808          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6809          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6810          * @param {String} selector The simple selector to test
6811          * @return {Boolean}
6812          */
6813         is : function(el, ss){
6814             if(typeof el == "string"){
6815                 el = document.getElementById(el);
6816             }
6817             var isArray = (el instanceof Array);
6818             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6819             return isArray ? (result.length == el.length) : (result.length > 0);
6820         },
6821
6822         /**
6823          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6824          * @param {Array} el An array of elements to filter
6825          * @param {String} selector The simple selector to test
6826          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6827          * the selector instead of the ones that match
6828          * @return {Array}
6829          */
6830         filter : function(els, ss, nonMatches){
6831             ss = ss.replace(trimRe, "");
6832             if(!simpleCache[ss]){
6833                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6834             }
6835             var result = simpleCache[ss](els);
6836             return nonMatches ? quickDiff(result, els) : result;
6837         },
6838
6839         /**
6840          * Collection of matching regular expressions and code snippets.
6841          */
6842         matchers : [{
6843                 re: /^\.([\w-]+)/,
6844                 select: 'n = byClassName(n, null, " {1} ");'
6845             }, {
6846                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6847                 select: 'n = byPseudo(n, "{1}", "{2}");'
6848             },{
6849                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6850                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6851             }, {
6852                 re: /^#([\w-]+)/,
6853                 select: 'n = byId(n, null, "{1}");'
6854             },{
6855                 re: /^@([\w-]+)/,
6856                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6857             }
6858         ],
6859
6860         /**
6861          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6862          * 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;.
6863          */
6864         operators : {
6865             "=" : function(a, v){
6866                 return a == v;
6867             },
6868             "!=" : function(a, v){
6869                 return a != v;
6870             },
6871             "^=" : function(a, v){
6872                 return a && a.substr(0, v.length) == v;
6873             },
6874             "$=" : function(a, v){
6875                 return a && a.substr(a.length-v.length) == v;
6876             },
6877             "*=" : function(a, v){
6878                 return a && a.indexOf(v) !== -1;
6879             },
6880             "%=" : function(a, v){
6881                 return (a % v) == 0;
6882             },
6883             "|=" : function(a, v){
6884                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6885             },
6886             "~=" : function(a, v){
6887                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6888             }
6889         },
6890
6891         /**
6892          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6893          * and the argument (if any) supplied in the selector.
6894          */
6895         pseudos : {
6896             "first-child" : function(c){
6897                 var r = [], ri = -1, n;
6898                 for(var i = 0, ci; ci = n = c[i]; i++){
6899                     while((n = n.previousSibling) && n.nodeType != 1);
6900                     if(!n){
6901                         r[++ri] = ci;
6902                     }
6903                 }
6904                 return r;
6905             },
6906
6907             "last-child" : function(c){
6908                 var r = [], ri = -1, n;
6909                 for(var i = 0, ci; ci = n = c[i]; i++){
6910                     while((n = n.nextSibling) && n.nodeType != 1);
6911                     if(!n){
6912                         r[++ri] = ci;
6913                     }
6914                 }
6915                 return r;
6916             },
6917
6918             "nth-child" : function(c, a) {
6919                 var r = [], ri = -1;
6920                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6921                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6922                 for(var i = 0, n; n = c[i]; i++){
6923                     var pn = n.parentNode;
6924                     if (batch != pn._batch) {
6925                         var j = 0;
6926                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6927                             if(cn.nodeType == 1){
6928                                cn.nodeIndex = ++j;
6929                             }
6930                         }
6931                         pn._batch = batch;
6932                     }
6933                     if (f == 1) {
6934                         if (l == 0 || n.nodeIndex == l){
6935                             r[++ri] = n;
6936                         }
6937                     } else if ((n.nodeIndex + l) % f == 0){
6938                         r[++ri] = n;
6939                     }
6940                 }
6941
6942                 return r;
6943             },
6944
6945             "only-child" : function(c){
6946                 var r = [], ri = -1;;
6947                 for(var i = 0, ci; ci = c[i]; i++){
6948                     if(!prev(ci) && !next(ci)){
6949                         r[++ri] = ci;
6950                     }
6951                 }
6952                 return r;
6953             },
6954
6955             "empty" : function(c){
6956                 var r = [], ri = -1;
6957                 for(var i = 0, ci; ci = c[i]; i++){
6958                     var cns = ci.childNodes, j = 0, cn, empty = true;
6959                     while(cn = cns[j]){
6960                         ++j;
6961                         if(cn.nodeType == 1 || cn.nodeType == 3){
6962                             empty = false;
6963                             break;
6964                         }
6965                     }
6966                     if(empty){
6967                         r[++ri] = ci;
6968                     }
6969                 }
6970                 return r;
6971             },
6972
6973             "contains" : function(c, v){
6974                 var r = [], ri = -1;
6975                 for(var i = 0, ci; ci = c[i]; i++){
6976                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6977                         r[++ri] = ci;
6978                     }
6979                 }
6980                 return r;
6981             },
6982
6983             "nodeValue" : function(c, v){
6984                 var r = [], ri = -1;
6985                 for(var i = 0, ci; ci = c[i]; i++){
6986                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6987                         r[++ri] = ci;
6988                     }
6989                 }
6990                 return r;
6991             },
6992
6993             "checked" : function(c){
6994                 var r = [], ri = -1;
6995                 for(var i = 0, ci; ci = c[i]; i++){
6996                     if(ci.checked == true){
6997                         r[++ri] = ci;
6998                     }
6999                 }
7000                 return r;
7001             },
7002
7003             "not" : function(c, ss){
7004                 return Roo.DomQuery.filter(c, ss, true);
7005             },
7006
7007             "odd" : function(c){
7008                 return this["nth-child"](c, "odd");
7009             },
7010
7011             "even" : function(c){
7012                 return this["nth-child"](c, "even");
7013             },
7014
7015             "nth" : function(c, a){
7016                 return c[a-1] || [];
7017             },
7018
7019             "first" : function(c){
7020                 return c[0] || [];
7021             },
7022
7023             "last" : function(c){
7024                 return c[c.length-1] || [];
7025             },
7026
7027             "has" : function(c, ss){
7028                 var s = Roo.DomQuery.select;
7029                 var r = [], ri = -1;
7030                 for(var i = 0, ci; ci = c[i]; i++){
7031                     if(s(ss, ci).length > 0){
7032                         r[++ri] = ci;
7033                     }
7034                 }
7035                 return r;
7036             },
7037
7038             "next" : function(c, ss){
7039                 var is = Roo.DomQuery.is;
7040                 var r = [], ri = -1;
7041                 for(var i = 0, ci; ci = c[i]; i++){
7042                     var n = next(ci);
7043                     if(n && is(n, ss)){
7044                         r[++ri] = ci;
7045                     }
7046                 }
7047                 return r;
7048             },
7049
7050             "prev" : function(c, ss){
7051                 var is = Roo.DomQuery.is;
7052                 var r = [], ri = -1;
7053                 for(var i = 0, ci; ci = c[i]; i++){
7054                     var n = prev(ci);
7055                     if(n && is(n, ss)){
7056                         r[++ri] = ci;
7057                     }
7058                 }
7059                 return r;
7060             }
7061         }
7062     };
7063 }();
7064
7065 /**
7066  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7067  * @param {String} path The selector/xpath query
7068  * @param {Node} root (optional) The start of the query (defaults to document).
7069  * @return {Array}
7070  * @member Roo
7071  * @method query
7072  */
7073 Roo.query = Roo.DomQuery.select;
7074 /*
7075  * Based on:
7076  * Ext JS Library 1.1.1
7077  * Copyright(c) 2006-2007, Ext JS, LLC.
7078  *
7079  * Originally Released Under LGPL - original licence link has changed is not relivant.
7080  *
7081  * Fork - LGPL
7082  * <script type="text/javascript">
7083  */
7084
7085 /**
7086  * @class Roo.util.Observable
7087  * Base class that provides a common interface for publishing events. Subclasses are expected to
7088  * to have a property "events" with all the events defined.<br>
7089  * For example:
7090  * <pre><code>
7091  Employee = function(name){
7092     this.name = name;
7093     this.addEvents({
7094         "fired" : true,
7095         "quit" : true
7096     });
7097  }
7098  Roo.extend(Employee, Roo.util.Observable);
7099 </code></pre>
7100  * @param {Object} config properties to use (incuding events / listeners)
7101  */
7102
7103 Roo.util.Observable = function(cfg){
7104     
7105     cfg = cfg|| {};
7106     this.addEvents(cfg.events || {});
7107     if (cfg.events) {
7108         delete cfg.events; // make sure
7109     }
7110      
7111     Roo.apply(this, cfg);
7112     
7113     if(this.listeners){
7114         this.on(this.listeners);
7115         delete this.listeners;
7116     }
7117 };
7118 Roo.util.Observable.prototype = {
7119     /** 
7120  * @cfg {Object} listeners  list of events and functions to call for this object, 
7121  * For example :
7122  * <pre><code>
7123     listeners :  { 
7124        'click' : function(e) {
7125            ..... 
7126         } ,
7127         .... 
7128     } 
7129   </code></pre>
7130  */
7131     
7132     
7133     /**
7134      * Fires the specified event with the passed parameters (minus the event name).
7135      * @param {String} eventName
7136      * @param {Object...} args Variable number of parameters are passed to handlers
7137      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7138      */
7139     fireEvent : function(){
7140         var ce = this.events[arguments[0].toLowerCase()];
7141         if(typeof ce == "object"){
7142             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7143         }else{
7144             return true;
7145         }
7146     },
7147
7148     // private
7149     filterOptRe : /^(?:scope|delay|buffer|single)$/,
7150
7151     /**
7152      * Appends an event handler to this component
7153      * @param {String}   eventName The type of event to listen for
7154      * @param {Function} handler The method the event invokes
7155      * @param {Object}   scope (optional) The scope in which to execute the handler
7156      * function. The handler function's "this" context.
7157      * @param {Object}   options (optional) An object containing handler configuration
7158      * properties. This may contain any of the following properties:<ul>
7159      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7160      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7161      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7162      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7163      * by the specified number of milliseconds. If the event fires again within that time, the original
7164      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7165      * </ul><br>
7166      * <p>
7167      * <b>Combining Options</b><br>
7168      * Using the options argument, it is possible to combine different types of listeners:<br>
7169      * <br>
7170      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7171                 <pre><code>
7172                 el.on('click', this.onClick, this, {
7173                         single: true,
7174                 delay: 100,
7175                 forumId: 4
7176                 });
7177                 </code></pre>
7178      * <p>
7179      * <b>Attaching multiple handlers in 1 call</b><br>
7180      * The method also allows for a single argument to be passed which is a config object containing properties
7181      * which specify multiple handlers.
7182      * <pre><code>
7183                 el.on({
7184                         'click': {
7185                         fn: this.onClick,
7186                         scope: this,
7187                         delay: 100
7188                 }, 
7189                 'mouseover': {
7190                         fn: this.onMouseOver,
7191                         scope: this
7192                 },
7193                 'mouseout': {
7194                         fn: this.onMouseOut,
7195                         scope: this
7196                 }
7197                 });
7198                 </code></pre>
7199      * <p>
7200      * Or a shorthand syntax which passes the same scope object to all handlers:
7201         <pre><code>
7202                 el.on({
7203                         'click': this.onClick,
7204                 'mouseover': this.onMouseOver,
7205                 'mouseout': this.onMouseOut,
7206                 scope: this
7207                 });
7208                 </code></pre>
7209      */
7210     addListener : function(eventName, fn, scope, o){
7211         if(typeof eventName == "object"){
7212             o = eventName;
7213             for(var e in o){
7214                 if(this.filterOptRe.test(e)){
7215                     continue;
7216                 }
7217                 if(typeof o[e] == "function"){
7218                     // shared options
7219                     this.addListener(e, o[e], o.scope,  o);
7220                 }else{
7221                     // individual options
7222                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7223                 }
7224             }
7225             return;
7226         }
7227         o = (!o || typeof o == "boolean") ? {} : o;
7228         eventName = eventName.toLowerCase();
7229         var ce = this.events[eventName] || true;
7230         if(typeof ce == "boolean"){
7231             ce = new Roo.util.Event(this, eventName);
7232             this.events[eventName] = ce;
7233         }
7234         ce.addListener(fn, scope, o);
7235     },
7236
7237     /**
7238      * Removes a listener
7239      * @param {String}   eventName     The type of event to listen for
7240      * @param {Function} handler        The handler to remove
7241      * @param {Object}   scope  (optional) The scope (this object) for the handler
7242      */
7243     removeListener : function(eventName, fn, scope){
7244         var ce = this.events[eventName.toLowerCase()];
7245         if(typeof ce == "object"){
7246             ce.removeListener(fn, scope);
7247         }
7248     },
7249
7250     /**
7251      * Removes all listeners for this object
7252      */
7253     purgeListeners : function(){
7254         for(var evt in this.events){
7255             if(typeof this.events[evt] == "object"){
7256                  this.events[evt].clearListeners();
7257             }
7258         }
7259     },
7260
7261     relayEvents : function(o, events){
7262         var createHandler = function(ename){
7263             return function(){
7264                  
7265                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7266             };
7267         };
7268         for(var i = 0, len = events.length; i < len; i++){
7269             var ename = events[i];
7270             if(!this.events[ename]){
7271                 this.events[ename] = true;
7272             };
7273             o.on(ename, createHandler(ename), this);
7274         }
7275     },
7276
7277     /**
7278      * Used to define events on this Observable
7279      * @param {Object} object The object with the events defined
7280      */
7281     addEvents : function(o){
7282         if(!this.events){
7283             this.events = {};
7284         }
7285         Roo.applyIf(this.events, o);
7286     },
7287
7288     /**
7289      * Checks to see if this object has any listeners for a specified event
7290      * @param {String} eventName The name of the event to check for
7291      * @return {Boolean} True if the event is being listened for, else false
7292      */
7293     hasListener : function(eventName){
7294         var e = this.events[eventName];
7295         return typeof e == "object" && e.listeners.length > 0;
7296     }
7297 };
7298 /**
7299  * Appends an event handler to this element (shorthand for addListener)
7300  * @param {String}   eventName     The type of event to listen for
7301  * @param {Function} handler        The method the event invokes
7302  * @param {Object}   scope (optional) The scope in which to execute the handler
7303  * function. The handler function's "this" context.
7304  * @param {Object}   options  (optional)
7305  * @method
7306  */
7307 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7308 /**
7309  * Removes a listener (shorthand for removeListener)
7310  * @param {String}   eventName     The type of event to listen for
7311  * @param {Function} handler        The handler to remove
7312  * @param {Object}   scope  (optional) The scope (this object) for the handler
7313  * @method
7314  */
7315 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7316
7317 /**
7318  * Starts capture on the specified Observable. All events will be passed
7319  * to the supplied function with the event name + standard signature of the event
7320  * <b>before</b> the event is fired. If the supplied function returns false,
7321  * the event will not fire.
7322  * @param {Observable} o The Observable to capture
7323  * @param {Function} fn The function to call
7324  * @param {Object} scope (optional) The scope (this object) for the fn
7325  * @static
7326  */
7327 Roo.util.Observable.capture = function(o, fn, scope){
7328     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7329 };
7330
7331 /**
7332  * Removes <b>all</b> added captures from the Observable.
7333  * @param {Observable} o The Observable to release
7334  * @static
7335  */
7336 Roo.util.Observable.releaseCapture = function(o){
7337     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7338 };
7339
7340 (function(){
7341
7342     var createBuffered = function(h, o, scope){
7343         var task = new Roo.util.DelayedTask();
7344         return function(){
7345             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7346         };
7347     };
7348
7349     var createSingle = function(h, e, fn, scope){
7350         return function(){
7351             e.removeListener(fn, scope);
7352             return h.apply(scope, arguments);
7353         };
7354     };
7355
7356     var createDelayed = function(h, o, scope){
7357         return function(){
7358             var args = Array.prototype.slice.call(arguments, 0);
7359             setTimeout(function(){
7360                 h.apply(scope, args);
7361             }, o.delay || 10);
7362         };
7363     };
7364
7365     Roo.util.Event = function(obj, name){
7366         this.name = name;
7367         this.obj = obj;
7368         this.listeners = [];
7369     };
7370
7371     Roo.util.Event.prototype = {
7372         addListener : function(fn, scope, options){
7373             var o = options || {};
7374             scope = scope || this.obj;
7375             if(!this.isListening(fn, scope)){
7376                 var l = {fn: fn, scope: scope, options: o};
7377                 var h = fn;
7378                 if(o.delay){
7379                     h = createDelayed(h, o, scope);
7380                 }
7381                 if(o.single){
7382                     h = createSingle(h, this, fn, scope);
7383                 }
7384                 if(o.buffer){
7385                     h = createBuffered(h, o, scope);
7386                 }
7387                 l.fireFn = h;
7388                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7389                     this.listeners.push(l);
7390                 }else{
7391                     this.listeners = this.listeners.slice(0);
7392                     this.listeners.push(l);
7393                 }
7394             }
7395         },
7396
7397         findListener : function(fn, scope){
7398             scope = scope || this.obj;
7399             var ls = this.listeners;
7400             for(var i = 0, len = ls.length; i < len; i++){
7401                 var l = ls[i];
7402                 if(l.fn == fn && l.scope == scope){
7403                     return i;
7404                 }
7405             }
7406             return -1;
7407         },
7408
7409         isListening : function(fn, scope){
7410             return this.findListener(fn, scope) != -1;
7411         },
7412
7413         removeListener : function(fn, scope){
7414             var index;
7415             if((index = this.findListener(fn, scope)) != -1){
7416                 if(!this.firing){
7417                     this.listeners.splice(index, 1);
7418                 }else{
7419                     this.listeners = this.listeners.slice(0);
7420                     this.listeners.splice(index, 1);
7421                 }
7422                 return true;
7423             }
7424             return false;
7425         },
7426
7427         clearListeners : function(){
7428             this.listeners = [];
7429         },
7430
7431         fire : function(){
7432             var ls = this.listeners, scope, len = ls.length;
7433             if(len > 0){
7434                 this.firing = true;
7435                 var args = Array.prototype.slice.call(arguments, 0);                
7436                 for(var i = 0; i < len; i++){
7437                     var l = ls[i];
7438                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7439                         this.firing = false;
7440                         return false;
7441                     }
7442                 }
7443                 this.firing = false;
7444             }
7445             return true;
7446         }
7447     };
7448 })();/*
7449  * RooJS Library 
7450  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7451  *
7452  * Licence LGPL 
7453  *
7454  */
7455  
7456 /**
7457  * @class Roo.Document
7458  * @extends Roo.util.Observable
7459  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7460  * 
7461  * @param {Object} config the methods and properties of the 'base' class for the application.
7462  * 
7463  *  Generic Page handler - implement this to start your app..
7464  * 
7465  * eg.
7466  *  MyProject = new Roo.Document({
7467         events : {
7468             'load' : true // your events..
7469         },
7470         listeners : {
7471             'ready' : function() {
7472                 // fired on Roo.onReady()
7473             }
7474         }
7475  * 
7476  */
7477 Roo.Document = function(cfg) {
7478      
7479     this.addEvents({ 
7480         'ready' : true
7481     });
7482     Roo.util.Observable.call(this,cfg);
7483     
7484     var _this = this;
7485     
7486     Roo.onReady(function() {
7487         _this.fireEvent('ready');
7488     },null,false);
7489     
7490     
7491 }
7492
7493 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7494  * Based on:
7495  * Ext JS Library 1.1.1
7496  * Copyright(c) 2006-2007, Ext JS, LLC.
7497  *
7498  * Originally Released Under LGPL - original licence link has changed is not relivant.
7499  *
7500  * Fork - LGPL
7501  * <script type="text/javascript">
7502  */
7503
7504 /**
7505  * @class Roo.EventManager
7506  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7507  * several useful events directly.
7508  * See {@link Roo.EventObject} for more details on normalized event objects.
7509  * @static
7510  */
7511 Roo.EventManager = function(){
7512     var docReadyEvent, docReadyProcId, docReadyState = false;
7513     var resizeEvent, resizeTask, textEvent, textSize;
7514     var E = Roo.lib.Event;
7515     var D = Roo.lib.Dom;
7516
7517     
7518     
7519
7520     var fireDocReady = function(){
7521         if(!docReadyState){
7522             docReadyState = true;
7523             Roo.isReady = true;
7524             if(docReadyProcId){
7525                 clearInterval(docReadyProcId);
7526             }
7527             if(Roo.isGecko || Roo.isOpera) {
7528                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7529             }
7530             if(Roo.isIE){
7531                 var defer = document.getElementById("ie-deferred-loader");
7532                 if(defer){
7533                     defer.onreadystatechange = null;
7534                     defer.parentNode.removeChild(defer);
7535                 }
7536             }
7537             if(docReadyEvent){
7538                 docReadyEvent.fire();
7539                 docReadyEvent.clearListeners();
7540             }
7541         }
7542     };
7543     
7544     var initDocReady = function(){
7545         docReadyEvent = new Roo.util.Event();
7546         if(Roo.isGecko || Roo.isOpera) {
7547             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7548         }else if(Roo.isIE){
7549             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7550             var defer = document.getElementById("ie-deferred-loader");
7551             defer.onreadystatechange = function(){
7552                 if(this.readyState == "complete"){
7553                     fireDocReady();
7554                 }
7555             };
7556         }else if(Roo.isSafari){ 
7557             docReadyProcId = setInterval(function(){
7558                 var rs = document.readyState;
7559                 if(rs == "complete") {
7560                     fireDocReady();     
7561                  }
7562             }, 10);
7563         }
7564         // no matter what, make sure it fires on load
7565         E.on(window, "load", fireDocReady);
7566     };
7567
7568     var createBuffered = function(h, o){
7569         var task = new Roo.util.DelayedTask(h);
7570         return function(e){
7571             // create new event object impl so new events don't wipe out properties
7572             e = new Roo.EventObjectImpl(e);
7573             task.delay(o.buffer, h, null, [e]);
7574         };
7575     };
7576
7577     var createSingle = function(h, el, ename, fn){
7578         return function(e){
7579             Roo.EventManager.removeListener(el, ename, fn);
7580             h(e);
7581         };
7582     };
7583
7584     var createDelayed = function(h, o){
7585         return function(e){
7586             // create new event object impl so new events don't wipe out properties
7587             e = new Roo.EventObjectImpl(e);
7588             setTimeout(function(){
7589                 h(e);
7590             }, o.delay || 10);
7591         };
7592     };
7593     var transitionEndVal = false;
7594     
7595     var transitionEnd = function()
7596     {
7597         if (transitionEndVal) {
7598             return transitionEndVal;
7599         }
7600         var el = document.createElement('div');
7601
7602         var transEndEventNames = {
7603             WebkitTransition : 'webkitTransitionEnd',
7604             MozTransition    : 'transitionend',
7605             OTransition      : 'oTransitionEnd otransitionend',
7606             transition       : 'transitionend'
7607         };
7608     
7609         for (var name in transEndEventNames) {
7610             if (el.style[name] !== undefined) {
7611                 transitionEndVal = transEndEventNames[name];
7612                 return  transitionEndVal ;
7613             }
7614         }
7615     }
7616     
7617   
7618
7619     var listen = function(element, ename, opt, fn, scope)
7620     {
7621         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7622         fn = fn || o.fn; scope = scope || o.scope;
7623         var el = Roo.getDom(element);
7624         
7625         
7626         if(!el){
7627             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7628         }
7629         
7630         if (ename == 'transitionend') {
7631             ename = transitionEnd();
7632         }
7633         var h = function(e){
7634             e = Roo.EventObject.setEvent(e);
7635             var t;
7636             if(o.delegate){
7637                 t = e.getTarget(o.delegate, el);
7638                 if(!t){
7639                     return;
7640                 }
7641             }else{
7642                 t = e.target;
7643             }
7644             if(o.stopEvent === true){
7645                 e.stopEvent();
7646             }
7647             if(o.preventDefault === true){
7648                e.preventDefault();
7649             }
7650             if(o.stopPropagation === true){
7651                 e.stopPropagation();
7652             }
7653
7654             if(o.normalized === false){
7655                 e = e.browserEvent;
7656             }
7657
7658             fn.call(scope || el, e, t, o);
7659         };
7660         if(o.delay){
7661             h = createDelayed(h, o);
7662         }
7663         if(o.single){
7664             h = createSingle(h, el, ename, fn);
7665         }
7666         if(o.buffer){
7667             h = createBuffered(h, o);
7668         }
7669         
7670         fn._handlers = fn._handlers || [];
7671         
7672         
7673         fn._handlers.push([Roo.id(el), ename, h]);
7674         
7675         
7676          
7677         E.on(el, ename, h); // this adds the actuall listener to the object..
7678         
7679         
7680         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7681             el.addEventListener("DOMMouseScroll", h, false);
7682             E.on(window, 'unload', function(){
7683                 el.removeEventListener("DOMMouseScroll", h, false);
7684             });
7685         }
7686         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7687             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7688         }
7689         return h;
7690     };
7691
7692     var stopListening = function(el, ename, fn){
7693         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7694         if(hds){
7695             for(var i = 0, len = hds.length; i < len; i++){
7696                 var h = hds[i];
7697                 if(h[0] == id && h[1] == ename){
7698                     hd = h[2];
7699                     hds.splice(i, 1);
7700                     break;
7701                 }
7702             }
7703         }
7704         E.un(el, ename, hd);
7705         el = Roo.getDom(el);
7706         if(ename == "mousewheel" && el.addEventListener){
7707             el.removeEventListener("DOMMouseScroll", hd, false);
7708         }
7709         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7710             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7711         }
7712     };
7713
7714     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7715     
7716     var pub = {
7717         
7718         
7719         /** 
7720          * Fix for doc tools
7721          * @scope Roo.EventManager
7722          */
7723         
7724         
7725         /** 
7726          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7727          * object with a Roo.EventObject
7728          * @param {Function} fn        The method the event invokes
7729          * @param {Object}   scope    An object that becomes the scope of the handler
7730          * @param {boolean}  override If true, the obj passed in becomes
7731          *                             the execution scope of the listener
7732          * @return {Function} The wrapped function
7733          * @deprecated
7734          */
7735         wrap : function(fn, scope, override){
7736             return function(e){
7737                 Roo.EventObject.setEvent(e);
7738                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7739             };
7740         },
7741         
7742         /**
7743      * Appends an event handler to an element (shorthand for addListener)
7744      * @param {String/HTMLElement}   element        The html element or id to assign the
7745      * @param {String}   eventName The type of event to listen for
7746      * @param {Function} handler The method the event invokes
7747      * @param {Object}   scope (optional) The scope in which to execute the handler
7748      * function. The handler function's "this" context.
7749      * @param {Object}   options (optional) An object containing handler configuration
7750      * properties. This may contain any of the following properties:<ul>
7751      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7752      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7753      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7754      * <li>preventDefault {Boolean} True to prevent the default action</li>
7755      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7756      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7757      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7758      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7759      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7760      * by the specified number of milliseconds. If the event fires again within that time, the original
7761      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7762      * </ul><br>
7763      * <p>
7764      * <b>Combining Options</b><br>
7765      * Using the options argument, it is possible to combine different types of listeners:<br>
7766      * <br>
7767      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7768      * Code:<pre><code>
7769 el.on('click', this.onClick, this, {
7770     single: true,
7771     delay: 100,
7772     stopEvent : true,
7773     forumId: 4
7774 });</code></pre>
7775      * <p>
7776      * <b>Attaching multiple handlers in 1 call</b><br>
7777       * The method also allows for a single argument to be passed which is a config object containing properties
7778      * which specify multiple handlers.
7779      * <p>
7780      * Code:<pre><code>
7781 el.on({
7782     'click' : {
7783         fn: this.onClick
7784         scope: this,
7785         delay: 100
7786     },
7787     'mouseover' : {
7788         fn: this.onMouseOver
7789         scope: this
7790     },
7791     'mouseout' : {
7792         fn: this.onMouseOut
7793         scope: this
7794     }
7795 });</code></pre>
7796      * <p>
7797      * Or a shorthand syntax:<br>
7798      * Code:<pre><code>
7799 el.on({
7800     'click' : this.onClick,
7801     'mouseover' : this.onMouseOver,
7802     'mouseout' : this.onMouseOut
7803     scope: this
7804 });</code></pre>
7805      */
7806         addListener : function(element, eventName, fn, scope, options){
7807             if(typeof eventName == "object"){
7808                 var o = eventName;
7809                 for(var e in o){
7810                     if(propRe.test(e)){
7811                         continue;
7812                     }
7813                     if(typeof o[e] == "function"){
7814                         // shared options
7815                         listen(element, e, o, o[e], o.scope);
7816                     }else{
7817                         // individual options
7818                         listen(element, e, o[e]);
7819                     }
7820                 }
7821                 return;
7822             }
7823             return listen(element, eventName, options, fn, scope);
7824         },
7825         
7826         /**
7827          * Removes an event handler
7828          *
7829          * @param {String/HTMLElement}   element        The id or html element to remove the 
7830          *                             event from
7831          * @param {String}   eventName     The type of event
7832          * @param {Function} fn
7833          * @return {Boolean} True if a listener was actually removed
7834          */
7835         removeListener : function(element, eventName, fn){
7836             return stopListening(element, eventName, fn);
7837         },
7838         
7839         /**
7840          * Fires when the document is ready (before onload and before images are loaded). Can be 
7841          * accessed shorthanded Roo.onReady().
7842          * @param {Function} fn        The method the event invokes
7843          * @param {Object}   scope    An  object that becomes the scope of the handler
7844          * @param {boolean}  options
7845          */
7846         onDocumentReady : function(fn, scope, options){
7847             if(docReadyState){ // if it already fired
7848                 docReadyEvent.addListener(fn, scope, options);
7849                 docReadyEvent.fire();
7850                 docReadyEvent.clearListeners();
7851                 return;
7852             }
7853             if(!docReadyEvent){
7854                 initDocReady();
7855             }
7856             docReadyEvent.addListener(fn, scope, options);
7857         },
7858         
7859         /**
7860          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7861          * @param {Function} fn        The method the event invokes
7862          * @param {Object}   scope    An object that becomes the scope of the handler
7863          * @param {boolean}  options
7864          */
7865         onWindowResize : function(fn, scope, options)
7866         {
7867             if(!resizeEvent){
7868                 resizeEvent = new Roo.util.Event();
7869                 resizeTask = new Roo.util.DelayedTask(function(){
7870                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7871                 });
7872                 E.on(window, "resize", function()
7873                 {
7874                     if (Roo.isIE) {
7875                         resizeTask.delay(50);
7876                     } else {
7877                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7878                     }
7879                 });
7880             }
7881             resizeEvent.addListener(fn, scope, options);
7882         },
7883
7884         /**
7885          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7886          * @param {Function} fn        The method the event invokes
7887          * @param {Object}   scope    An object that becomes the scope of the handler
7888          * @param {boolean}  options
7889          */
7890         onTextResize : function(fn, scope, options){
7891             if(!textEvent){
7892                 textEvent = new Roo.util.Event();
7893                 var textEl = new Roo.Element(document.createElement('div'));
7894                 textEl.dom.className = 'x-text-resize';
7895                 textEl.dom.innerHTML = 'X';
7896                 textEl.appendTo(document.body);
7897                 textSize = textEl.dom.offsetHeight;
7898                 setInterval(function(){
7899                     if(textEl.dom.offsetHeight != textSize){
7900                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7901                     }
7902                 }, this.textResizeInterval);
7903             }
7904             textEvent.addListener(fn, scope, options);
7905         },
7906
7907         /**
7908          * Removes the passed window resize listener.
7909          * @param {Function} fn        The method the event invokes
7910          * @param {Object}   scope    The scope of handler
7911          */
7912         removeResizeListener : function(fn, scope){
7913             if(resizeEvent){
7914                 resizeEvent.removeListener(fn, scope);
7915             }
7916         },
7917
7918         // private
7919         fireResize : function(){
7920             if(resizeEvent){
7921                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7922             }   
7923         },
7924         /**
7925          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7926          */
7927         ieDeferSrc : false,
7928         /**
7929          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7930          */
7931         textResizeInterval : 50
7932     };
7933     
7934     /**
7935      * Fix for doc tools
7936      * @scopeAlias pub=Roo.EventManager
7937      */
7938     
7939      /**
7940      * Appends an event handler to an element (shorthand for addListener)
7941      * @param {String/HTMLElement}   element        The html element or id to assign the
7942      * @param {String}   eventName The type of event to listen for
7943      * @param {Function} handler The method the event invokes
7944      * @param {Object}   scope (optional) The scope in which to execute the handler
7945      * function. The handler function's "this" context.
7946      * @param {Object}   options (optional) An object containing handler configuration
7947      * properties. This may contain any of the following properties:<ul>
7948      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7949      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7950      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7951      * <li>preventDefault {Boolean} True to prevent the default action</li>
7952      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7953      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7954      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7955      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7956      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7957      * by the specified number of milliseconds. If the event fires again within that time, the original
7958      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7959      * </ul><br>
7960      * <p>
7961      * <b>Combining Options</b><br>
7962      * Using the options argument, it is possible to combine different types of listeners:<br>
7963      * <br>
7964      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7965      * Code:<pre><code>
7966 el.on('click', this.onClick, this, {
7967     single: true,
7968     delay: 100,
7969     stopEvent : true,
7970     forumId: 4
7971 });</code></pre>
7972      * <p>
7973      * <b>Attaching multiple handlers in 1 call</b><br>
7974       * The method also allows for a single argument to be passed which is a config object containing properties
7975      * which specify multiple handlers.
7976      * <p>
7977      * Code:<pre><code>
7978 el.on({
7979     'click' : {
7980         fn: this.onClick
7981         scope: this,
7982         delay: 100
7983     },
7984     'mouseover' : {
7985         fn: this.onMouseOver
7986         scope: this
7987     },
7988     'mouseout' : {
7989         fn: this.onMouseOut
7990         scope: this
7991     }
7992 });</code></pre>
7993      * <p>
7994      * Or a shorthand syntax:<br>
7995      * Code:<pre><code>
7996 el.on({
7997     'click' : this.onClick,
7998     'mouseover' : this.onMouseOver,
7999     'mouseout' : this.onMouseOut
8000     scope: this
8001 });</code></pre>
8002      */
8003     pub.on = pub.addListener;
8004     pub.un = pub.removeListener;
8005
8006     pub.stoppedMouseDownEvent = new Roo.util.Event();
8007     return pub;
8008 }();
8009 /**
8010   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
8011   * @param {Function} fn        The method the event invokes
8012   * @param {Object}   scope    An  object that becomes the scope of the handler
8013   * @param {boolean}  override If true, the obj passed in becomes
8014   *                             the execution scope of the listener
8015   * @member Roo
8016   * @method onReady
8017  */
8018 Roo.onReady = Roo.EventManager.onDocumentReady;
8019
8020 Roo.onReady(function(){
8021     var bd = Roo.get(document.body);
8022     if(!bd){ return; }
8023
8024     var cls = [
8025             Roo.isIE ? "roo-ie"
8026             : Roo.isIE11 ? "roo-ie11"
8027             : Roo.isEdge ? "roo-edge"
8028             : Roo.isGecko ? "roo-gecko"
8029             : Roo.isOpera ? "roo-opera"
8030             : Roo.isSafari ? "roo-safari" : ""];
8031
8032     if(Roo.isMac){
8033         cls.push("roo-mac");
8034     }
8035     if(Roo.isLinux){
8036         cls.push("roo-linux");
8037     }
8038     if(Roo.isIOS){
8039         cls.push("roo-ios");
8040     }
8041     if(Roo.isTouch){
8042         cls.push("roo-touch");
8043     }
8044     if(Roo.isBorderBox){
8045         cls.push('roo-border-box');
8046     }
8047     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8048         var p = bd.dom.parentNode;
8049         if(p){
8050             p.className += ' roo-strict';
8051         }
8052     }
8053     bd.addClass(cls.join(' '));
8054 });
8055
8056 /**
8057  * @class Roo.EventObject
8058  * EventObject exposes the Yahoo! UI Event functionality directly on the object
8059  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
8060  * Example:
8061  * <pre><code>
8062  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8063     e.preventDefault();
8064     var target = e.getTarget();
8065     ...
8066  }
8067  var myDiv = Roo.get("myDiv");
8068  myDiv.on("click", handleClick);
8069  //or
8070  Roo.EventManager.on("myDiv", 'click', handleClick);
8071  Roo.EventManager.addListener("myDiv", 'click', handleClick);
8072  </code></pre>
8073  * @static
8074  */
8075 Roo.EventObject = function(){
8076     
8077     var E = Roo.lib.Event;
8078     
8079     // safari keypress events for special keys return bad keycodes
8080     var safariKeys = {
8081         63234 : 37, // left
8082         63235 : 39, // right
8083         63232 : 38, // up
8084         63233 : 40, // down
8085         63276 : 33, // page up
8086         63277 : 34, // page down
8087         63272 : 46, // delete
8088         63273 : 36, // home
8089         63275 : 35  // end
8090     };
8091
8092     // normalize button clicks
8093     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8094                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8095
8096     Roo.EventObjectImpl = function(e){
8097         if(e){
8098             this.setEvent(e.browserEvent || e);
8099         }
8100     };
8101     Roo.EventObjectImpl.prototype = {
8102         /**
8103          * Used to fix doc tools.
8104          * @scope Roo.EventObject.prototype
8105          */
8106             
8107
8108         
8109         
8110         /** The normal browser event */
8111         browserEvent : null,
8112         /** The button pressed in a mouse event */
8113         button : -1,
8114         /** True if the shift key was down during the event */
8115         shiftKey : false,
8116         /** True if the control key was down during the event */
8117         ctrlKey : false,
8118         /** True if the alt key was down during the event */
8119         altKey : false,
8120
8121         /** Key constant 
8122         * @type Number */
8123         BACKSPACE : 8,
8124         /** Key constant 
8125         * @type Number */
8126         TAB : 9,
8127         /** Key constant 
8128         * @type Number */
8129         RETURN : 13,
8130         /** Key constant 
8131         * @type Number */
8132         ENTER : 13,
8133         /** Key constant 
8134         * @type Number */
8135         SHIFT : 16,
8136         /** Key constant 
8137         * @type Number */
8138         CONTROL : 17,
8139         /** Key constant 
8140         * @type Number */
8141         ESC : 27,
8142         /** Key constant 
8143         * @type Number */
8144         SPACE : 32,
8145         /** Key constant 
8146         * @type Number */
8147         PAGEUP : 33,
8148         /** Key constant 
8149         * @type Number */
8150         PAGEDOWN : 34,
8151         /** Key constant 
8152         * @type Number */
8153         END : 35,
8154         /** Key constant 
8155         * @type Number */
8156         HOME : 36,
8157         /** Key constant 
8158         * @type Number */
8159         LEFT : 37,
8160         /** Key constant 
8161         * @type Number */
8162         UP : 38,
8163         /** Key constant 
8164         * @type Number */
8165         RIGHT : 39,
8166         /** Key constant 
8167         * @type Number */
8168         DOWN : 40,
8169         /** Key constant 
8170         * @type Number */
8171         DELETE : 46,
8172         /** Key constant 
8173         * @type Number */
8174         F5 : 116,
8175
8176            /** @private */
8177         setEvent : function(e){
8178             if(e == this || (e && e.browserEvent)){ // already wrapped
8179                 return e;
8180             }
8181             this.browserEvent = e;
8182             if(e){
8183                 // normalize buttons
8184                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8185                 if(e.type == 'click' && this.button == -1){
8186                     this.button = 0;
8187                 }
8188                 this.type = e.type;
8189                 this.shiftKey = e.shiftKey;
8190                 // mac metaKey behaves like ctrlKey
8191                 this.ctrlKey = e.ctrlKey || e.metaKey;
8192                 this.altKey = e.altKey;
8193                 // in getKey these will be normalized for the mac
8194                 this.keyCode = e.keyCode;
8195                 // keyup warnings on firefox.
8196                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8197                 // cache the target for the delayed and or buffered events
8198                 this.target = E.getTarget(e);
8199                 // same for XY
8200                 this.xy = E.getXY(e);
8201             }else{
8202                 this.button = -1;
8203                 this.shiftKey = false;
8204                 this.ctrlKey = false;
8205                 this.altKey = false;
8206                 this.keyCode = 0;
8207                 this.charCode =0;
8208                 this.target = null;
8209                 this.xy = [0, 0];
8210             }
8211             return this;
8212         },
8213
8214         /**
8215          * Stop the event (preventDefault and stopPropagation)
8216          */
8217         stopEvent : function(){
8218             if(this.browserEvent){
8219                 if(this.browserEvent.type == 'mousedown'){
8220                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8221                 }
8222                 E.stopEvent(this.browserEvent);
8223             }
8224         },
8225
8226         /**
8227          * Prevents the browsers default handling of the event.
8228          */
8229         preventDefault : function(){
8230             if(this.browserEvent){
8231                 E.preventDefault(this.browserEvent);
8232             }
8233         },
8234
8235         /** @private */
8236         isNavKeyPress : function(){
8237             var k = this.keyCode;
8238             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8239             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8240         },
8241
8242         isSpecialKey : function(){
8243             var k = this.keyCode;
8244             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8245             (k == 16) || (k == 17) ||
8246             (k >= 18 && k <= 20) ||
8247             (k >= 33 && k <= 35) ||
8248             (k >= 36 && k <= 39) ||
8249             (k >= 44 && k <= 45);
8250         },
8251         /**
8252          * Cancels bubbling of the event.
8253          */
8254         stopPropagation : function(){
8255             if(this.browserEvent){
8256                 if(this.type == 'mousedown'){
8257                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8258                 }
8259                 E.stopPropagation(this.browserEvent);
8260             }
8261         },
8262
8263         /**
8264          * Gets the key code for the event.
8265          * @return {Number}
8266          */
8267         getCharCode : function(){
8268             return this.charCode || this.keyCode;
8269         },
8270
8271         /**
8272          * Returns a normalized keyCode for the event.
8273          * @return {Number} The key code
8274          */
8275         getKey : function(){
8276             var k = this.keyCode || this.charCode;
8277             return Roo.isSafari ? (safariKeys[k] || k) : k;
8278         },
8279
8280         /**
8281          * Gets the x coordinate of the event.
8282          * @return {Number}
8283          */
8284         getPageX : function(){
8285             return this.xy[0];
8286         },
8287
8288         /**
8289          * Gets the y coordinate of the event.
8290          * @return {Number}
8291          */
8292         getPageY : function(){
8293             return this.xy[1];
8294         },
8295
8296         /**
8297          * Gets the time of the event.
8298          * @return {Number}
8299          */
8300         getTime : function(){
8301             if(this.browserEvent){
8302                 return E.getTime(this.browserEvent);
8303             }
8304             return null;
8305         },
8306
8307         /**
8308          * Gets the page coordinates of the event.
8309          * @return {Array} The xy values like [x, y]
8310          */
8311         getXY : function(){
8312             return this.xy;
8313         },
8314
8315         /**
8316          * Gets the target for the event.
8317          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8318          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8319                 search as a number or element (defaults to 10 || document.body)
8320          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8321          * @return {HTMLelement}
8322          */
8323         getTarget : function(selector, maxDepth, returnEl){
8324             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8325         },
8326         /**
8327          * Gets the related target.
8328          * @return {HTMLElement}
8329          */
8330         getRelatedTarget : function(){
8331             if(this.browserEvent){
8332                 return E.getRelatedTarget(this.browserEvent);
8333             }
8334             return null;
8335         },
8336
8337         /**
8338          * Normalizes mouse wheel delta across browsers
8339          * @return {Number} The delta
8340          */
8341         getWheelDelta : function(){
8342             var e = this.browserEvent;
8343             var delta = 0;
8344             if(e.wheelDelta){ /* IE/Opera. */
8345                 delta = e.wheelDelta/120;
8346             }else if(e.detail){ /* Mozilla case. */
8347                 delta = -e.detail/3;
8348             }
8349             return delta;
8350         },
8351
8352         /**
8353          * Returns true if the control, meta, shift or alt key was pressed during this event.
8354          * @return {Boolean}
8355          */
8356         hasModifier : function(){
8357             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8358         },
8359
8360         /**
8361          * Returns true if the target of this event equals el or is a child of el
8362          * @param {String/HTMLElement/Element} el
8363          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8364          * @return {Boolean}
8365          */
8366         within : function(el, related){
8367             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8368             return t && Roo.fly(el).contains(t);
8369         },
8370
8371         getPoint : function(){
8372             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8373         }
8374     };
8375
8376     return new Roo.EventObjectImpl();
8377 }();
8378             
8379     /*
8380  * Based on:
8381  * Ext JS Library 1.1.1
8382  * Copyright(c) 2006-2007, Ext JS, LLC.
8383  *
8384  * Originally Released Under LGPL - original licence link has changed is not relivant.
8385  *
8386  * Fork - LGPL
8387  * <script type="text/javascript">
8388  */
8389
8390  
8391 // was in Composite Element!??!?!
8392  
8393 (function(){
8394     var D = Roo.lib.Dom;
8395     var E = Roo.lib.Event;
8396     var A = Roo.lib.Anim;
8397
8398     // local style camelizing for speed
8399     var propCache = {};
8400     var camelRe = /(-[a-z])/gi;
8401     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8402     var view = document.defaultView;
8403
8404 /**
8405  * @class Roo.Element
8406  * Represents an Element in the DOM.<br><br>
8407  * Usage:<br>
8408 <pre><code>
8409 var el = Roo.get("my-div");
8410
8411 // or with getEl
8412 var el = getEl("my-div");
8413
8414 // or with a DOM element
8415 var el = Roo.get(myDivElement);
8416 </code></pre>
8417  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8418  * each call instead of constructing a new one.<br><br>
8419  * <b>Animations</b><br />
8420  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8421  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8422 <pre>
8423 Option    Default   Description
8424 --------- --------  ---------------------------------------------
8425 duration  .35       The duration of the animation in seconds
8426 easing    easeOut   The YUI easing method
8427 callback  none      A function to execute when the anim completes
8428 scope     this      The scope (this) of the callback function
8429 </pre>
8430 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8431 * manipulate the animation. Here's an example:
8432 <pre><code>
8433 var el = Roo.get("my-div");
8434
8435 // no animation
8436 el.setWidth(100);
8437
8438 // default animation
8439 el.setWidth(100, true);
8440
8441 // animation with some options set
8442 el.setWidth(100, {
8443     duration: 1,
8444     callback: this.foo,
8445     scope: this
8446 });
8447
8448 // using the "anim" property to get the Anim object
8449 var opt = {
8450     duration: 1,
8451     callback: this.foo,
8452     scope: this
8453 };
8454 el.setWidth(100, opt);
8455 ...
8456 if(opt.anim.isAnimated()){
8457     opt.anim.stop();
8458 }
8459 </code></pre>
8460 * <b> Composite (Collections of) Elements</b><br />
8461  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8462  * @constructor Create a new Element directly.
8463  * @param {String/HTMLElement} element
8464  * @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).
8465  */
8466     Roo.Element = function(element, forceNew)
8467     {
8468         var dom = typeof element == "string" ?
8469                 document.getElementById(element) : element;
8470         
8471         this.listeners = {};
8472         
8473         if(!dom){ // invalid id/element
8474             return null;
8475         }
8476         var id = dom.id;
8477         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8478             return Roo.Element.cache[id];
8479         }
8480
8481         /**
8482          * The DOM element
8483          * @type HTMLElement
8484          */
8485         this.dom = dom;
8486
8487         /**
8488          * The DOM element ID
8489          * @type String
8490          */
8491         this.id = id || Roo.id(dom);
8492         
8493         return this; // assumed for cctor?
8494     };
8495
8496     var El = Roo.Element;
8497
8498     El.prototype = {
8499         /**
8500          * The element's default display mode  (defaults to "") 
8501          * @type String
8502          */
8503         originalDisplay : "",
8504
8505         
8506         // note this is overridden in BS version..
8507         visibilityMode : 1, 
8508         /**
8509          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8510          * @type String
8511          */
8512         defaultUnit : "px",
8513         
8514         /**
8515          * Sets the element's visibility mode. When setVisible() is called it
8516          * will use this to determine whether to set the visibility or the display property.
8517          * @param visMode Element.VISIBILITY or Element.DISPLAY
8518          * @return {Roo.Element} this
8519          */
8520         setVisibilityMode : function(visMode){
8521             this.visibilityMode = visMode;
8522             return this;
8523         },
8524         /**
8525          * Convenience method for setVisibilityMode(Element.DISPLAY)
8526          * @param {String} display (optional) What to set display to when visible
8527          * @return {Roo.Element} this
8528          */
8529         enableDisplayMode : function(display){
8530             this.setVisibilityMode(El.DISPLAY);
8531             if(typeof display != "undefined") { this.originalDisplay = display; }
8532             return this;
8533         },
8534
8535         /**
8536          * 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)
8537          * @param {String} selector The simple selector to test
8538          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8539                 search as a number or element (defaults to 10 || document.body)
8540          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8541          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8542          */
8543         findParent : function(simpleSelector, maxDepth, returnEl){
8544             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8545             maxDepth = maxDepth || 50;
8546             if(typeof maxDepth != "number"){
8547                 stopEl = Roo.getDom(maxDepth);
8548                 maxDepth = 10;
8549             }
8550             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8551                 if(dq.is(p, simpleSelector)){
8552                     return returnEl ? Roo.get(p) : p;
8553                 }
8554                 depth++;
8555                 p = p.parentNode;
8556             }
8557             return null;
8558         },
8559
8560
8561         /**
8562          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8563          * @param {String} selector The simple selector to test
8564          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8565                 search as a number or element (defaults to 10 || document.body)
8566          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8567          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8568          */
8569         findParentNode : function(simpleSelector, maxDepth, returnEl){
8570             var p = Roo.fly(this.dom.parentNode, '_internal');
8571             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8572         },
8573         
8574         /**
8575          * Looks at  the scrollable parent element
8576          */
8577         findScrollableParent : function()
8578         {
8579             var overflowRegex = /(auto|scroll)/;
8580             
8581             if(this.getStyle('position') === 'fixed'){
8582                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8583             }
8584             
8585             var excludeStaticParent = this.getStyle('position') === "absolute";
8586             
8587             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8588                 
8589                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8590                     continue;
8591                 }
8592                 
8593                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8594                     return parent;
8595                 }
8596                 
8597                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8598                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8599                 }
8600             }
8601             
8602             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8603         },
8604
8605         /**
8606          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8607          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8608          * @param {String} selector The simple selector to test
8609          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8610                 search as a number or element (defaults to 10 || document.body)
8611          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8612          */
8613         up : function(simpleSelector, maxDepth){
8614             return this.findParentNode(simpleSelector, maxDepth, true);
8615         },
8616
8617
8618
8619         /**
8620          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8621          * @param {String} selector The simple selector to test
8622          * @return {Boolean} True if this element matches the selector, else false
8623          */
8624         is : function(simpleSelector){
8625             return Roo.DomQuery.is(this.dom, simpleSelector);
8626         },
8627
8628         /**
8629          * Perform animation on this element.
8630          * @param {Object} args The YUI animation control args
8631          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8632          * @param {Function} onComplete (optional) Function to call when animation completes
8633          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8634          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8635          * @return {Roo.Element} this
8636          */
8637         animate : function(args, duration, onComplete, easing, animType){
8638             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8639             return this;
8640         },
8641
8642         /*
8643          * @private Internal animation call
8644          */
8645         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8646             animType = animType || 'run';
8647             opt = opt || {};
8648             var anim = Roo.lib.Anim[animType](
8649                 this.dom, args,
8650                 (opt.duration || defaultDur) || .35,
8651                 (opt.easing || defaultEase) || 'easeOut',
8652                 function(){
8653                     Roo.callback(cb, this);
8654                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8655                 },
8656                 this
8657             );
8658             opt.anim = anim;
8659             return anim;
8660         },
8661
8662         // private legacy anim prep
8663         preanim : function(a, i){
8664             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8665         },
8666
8667         /**
8668          * Removes worthless text nodes
8669          * @param {Boolean} forceReclean (optional) By default the element
8670          * keeps track if it has been cleaned already so
8671          * you can call this over and over. However, if you update the element and
8672          * need to force a reclean, you can pass true.
8673          */
8674         clean : function(forceReclean){
8675             if(this.isCleaned && forceReclean !== true){
8676                 return this;
8677             }
8678             var ns = /\S/;
8679             var d = this.dom, n = d.firstChild, ni = -1;
8680             while(n){
8681                 var nx = n.nextSibling;
8682                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8683                     d.removeChild(n);
8684                 }else{
8685                     n.nodeIndex = ++ni;
8686                 }
8687                 n = nx;
8688             }
8689             this.isCleaned = true;
8690             return this;
8691         },
8692
8693         // private
8694         calcOffsetsTo : function(el){
8695             el = Roo.get(el);
8696             var d = el.dom;
8697             var restorePos = false;
8698             if(el.getStyle('position') == 'static'){
8699                 el.position('relative');
8700                 restorePos = true;
8701             }
8702             var x = 0, y =0;
8703             var op = this.dom;
8704             while(op && op != d && op.tagName != 'HTML'){
8705                 x+= op.offsetLeft;
8706                 y+= op.offsetTop;
8707                 op = op.offsetParent;
8708             }
8709             if(restorePos){
8710                 el.position('static');
8711             }
8712             return [x, y];
8713         },
8714
8715         /**
8716          * Scrolls this element into view within the passed container.
8717          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8718          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8719          * @return {Roo.Element} this
8720          */
8721         scrollIntoView : function(container, hscroll){
8722             var c = Roo.getDom(container) || document.body;
8723             var el = this.dom;
8724
8725             var o = this.calcOffsetsTo(c),
8726                 l = o[0],
8727                 t = o[1],
8728                 b = t+el.offsetHeight,
8729                 r = l+el.offsetWidth;
8730
8731             var ch = c.clientHeight;
8732             var ct = parseInt(c.scrollTop, 10);
8733             var cl = parseInt(c.scrollLeft, 10);
8734             var cb = ct + ch;
8735             var cr = cl + c.clientWidth;
8736
8737             if(t < ct){
8738                 c.scrollTop = t;
8739             }else if(b > cb){
8740                 c.scrollTop = b-ch;
8741             }
8742
8743             if(hscroll !== false){
8744                 if(l < cl){
8745                     c.scrollLeft = l;
8746                 }else if(r > cr){
8747                     c.scrollLeft = r-c.clientWidth;
8748                 }
8749             }
8750             return this;
8751         },
8752
8753         // private
8754         scrollChildIntoView : function(child, hscroll){
8755             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8756         },
8757
8758         /**
8759          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8760          * the new height may not be available immediately.
8761          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8762          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8763          * @param {Function} onComplete (optional) Function to call when animation completes
8764          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8765          * @return {Roo.Element} this
8766          */
8767         autoHeight : function(animate, duration, onComplete, easing){
8768             var oldHeight = this.getHeight();
8769             this.clip();
8770             this.setHeight(1); // force clipping
8771             setTimeout(function(){
8772                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8773                 if(!animate){
8774                     this.setHeight(height);
8775                     this.unclip();
8776                     if(typeof onComplete == "function"){
8777                         onComplete();
8778                     }
8779                 }else{
8780                     this.setHeight(oldHeight); // restore original height
8781                     this.setHeight(height, animate, duration, function(){
8782                         this.unclip();
8783                         if(typeof onComplete == "function") { onComplete(); }
8784                     }.createDelegate(this), easing);
8785                 }
8786             }.createDelegate(this), 0);
8787             return this;
8788         },
8789
8790         /**
8791          * Returns true if this element is an ancestor of the passed element
8792          * @param {HTMLElement/String} el The element to check
8793          * @return {Boolean} True if this element is an ancestor of el, else false
8794          */
8795         contains : function(el){
8796             if(!el){return false;}
8797             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8798         },
8799
8800         /**
8801          * Checks whether the element is currently visible using both visibility and display properties.
8802          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8803          * @return {Boolean} True if the element is currently visible, else false
8804          */
8805         isVisible : function(deep) {
8806             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8807             if(deep !== true || !vis){
8808                 return vis;
8809             }
8810             var p = this.dom.parentNode;
8811             while(p && p.tagName.toLowerCase() != "body"){
8812                 if(!Roo.fly(p, '_isVisible').isVisible()){
8813                     return false;
8814                 }
8815                 p = p.parentNode;
8816             }
8817             return true;
8818         },
8819
8820         /**
8821          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8822          * @param {String} selector The CSS selector
8823          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8824          * @return {CompositeElement/CompositeElementLite} The composite element
8825          */
8826         select : function(selector, unique){
8827             return El.select(selector, unique, this.dom);
8828         },
8829
8830         /**
8831          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8832          * @param {String} selector The CSS selector
8833          * @return {Array} An array of the matched nodes
8834          */
8835         query : function(selector, unique){
8836             return Roo.DomQuery.select(selector, this.dom);
8837         },
8838
8839         /**
8840          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8841          * @param {String} selector The CSS selector
8842          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8843          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8844          */
8845         child : function(selector, returnDom){
8846             var n = Roo.DomQuery.selectNode(selector, this.dom);
8847             return returnDom ? n : Roo.get(n);
8848         },
8849
8850         /**
8851          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8852          * @param {String} selector The CSS selector
8853          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8854          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8855          */
8856         down : function(selector, returnDom){
8857             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8858             return returnDom ? n : Roo.get(n);
8859         },
8860
8861         /**
8862          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8863          * @param {String} group The group the DD object is member of
8864          * @param {Object} config The DD config object
8865          * @param {Object} overrides An object containing methods to override/implement on the DD object
8866          * @return {Roo.dd.DD} The DD object
8867          */
8868         initDD : function(group, config, overrides){
8869             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8870             return Roo.apply(dd, overrides);
8871         },
8872
8873         /**
8874          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8875          * @param {String} group The group the DDProxy object is member of
8876          * @param {Object} config The DDProxy config object
8877          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8878          * @return {Roo.dd.DDProxy} The DDProxy object
8879          */
8880         initDDProxy : function(group, config, overrides){
8881             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8882             return Roo.apply(dd, overrides);
8883         },
8884
8885         /**
8886          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8887          * @param {String} group The group the DDTarget object is member of
8888          * @param {Object} config The DDTarget config object
8889          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8890          * @return {Roo.dd.DDTarget} The DDTarget object
8891          */
8892         initDDTarget : function(group, config, overrides){
8893             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8894             return Roo.apply(dd, overrides);
8895         },
8896
8897         /**
8898          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8899          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8900          * @param {Boolean} visible Whether the element is visible
8901          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8902          * @return {Roo.Element} this
8903          */
8904          setVisible : function(visible, animate){
8905             if(!animate || !A){
8906                 if(this.visibilityMode == El.DISPLAY){
8907                     this.setDisplayed(visible);
8908                 }else{
8909                     this.fixDisplay();
8910                     this.dom.style.visibility = visible ? "visible" : "hidden";
8911                 }
8912             }else{
8913                 // closure for composites
8914                 var dom = this.dom;
8915                 var visMode = this.visibilityMode;
8916                 if(visible){
8917                     this.setOpacity(.01);
8918                     this.setVisible(true);
8919                 }
8920                 this.anim({opacity: { to: (visible?1:0) }},
8921                       this.preanim(arguments, 1),
8922                       null, .35, 'easeIn', function(){
8923                          if(!visible){
8924                              if(visMode == El.DISPLAY){
8925                                  dom.style.display = "none";
8926                              }else{
8927                                  dom.style.visibility = "hidden";
8928                              }
8929                              Roo.get(dom).setOpacity(1);
8930                          }
8931                      });
8932             }
8933             return this;
8934         },
8935
8936         /**
8937          * Returns true if display is not "none"
8938          * @return {Boolean}
8939          */
8940         isDisplayed : function() {
8941             return this.getStyle("display") != "none";
8942         },
8943
8944         /**
8945          * Toggles the element's visibility or display, depending on visibility mode.
8946          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8947          * @return {Roo.Element} this
8948          */
8949         toggle : function(animate){
8950             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8951             return this;
8952         },
8953
8954         /**
8955          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8956          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8957          * @return {Roo.Element} this
8958          */
8959         setDisplayed : function(value) {
8960             if(typeof value == "boolean"){
8961                value = value ? this.originalDisplay : "none";
8962             }
8963             this.setStyle("display", value);
8964             return this;
8965         },
8966
8967         /**
8968          * Tries to focus the element. Any exceptions are caught and ignored.
8969          * @return {Roo.Element} this
8970          */
8971         focus : function() {
8972             try{
8973                 this.dom.focus();
8974             }catch(e){}
8975             return this;
8976         },
8977
8978         /**
8979          * Tries to blur the element. Any exceptions are caught and ignored.
8980          * @return {Roo.Element} this
8981          */
8982         blur : function() {
8983             try{
8984                 this.dom.blur();
8985             }catch(e){}
8986             return this;
8987         },
8988
8989         /**
8990          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8991          * @param {String/Array} className The CSS class to add, or an array of classes
8992          * @return {Roo.Element} this
8993          */
8994         addClass : function(className){
8995             if(className instanceof Array){
8996                 for(var i = 0, len = className.length; i < len; i++) {
8997                     this.addClass(className[i]);
8998                 }
8999             }else{
9000                 if(className && !this.hasClass(className)){
9001                     if (this.dom instanceof SVGElement) {
9002                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
9003                     } else {
9004                         this.dom.className = this.dom.className + " " + className;
9005                     }
9006                 }
9007             }
9008             return this;
9009         },
9010
9011         /**
9012          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9013          * @param {String/Array} className The CSS class to add, or an array of classes
9014          * @return {Roo.Element} this
9015          */
9016         radioClass : function(className){
9017             var siblings = this.dom.parentNode.childNodes;
9018             for(var i = 0; i < siblings.length; i++) {
9019                 var s = siblings[i];
9020                 if(s.nodeType == 1){
9021                     Roo.get(s).removeClass(className);
9022                 }
9023             }
9024             this.addClass(className);
9025             return this;
9026         },
9027
9028         /**
9029          * Removes one or more CSS classes from the element.
9030          * @param {String/Array} className The CSS class to remove, or an array of classes
9031          * @return {Roo.Element} this
9032          */
9033         removeClass : function(className){
9034             
9035             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9036             if(!className || !cn){
9037                 return this;
9038             }
9039             if(className instanceof Array){
9040                 for(var i = 0, len = className.length; i < len; i++) {
9041                     this.removeClass(className[i]);
9042                 }
9043             }else{
9044                 if(this.hasClass(className)){
9045                     var re = this.classReCache[className];
9046                     if (!re) {
9047                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9048                        this.classReCache[className] = re;
9049                     }
9050                     if (this.dom instanceof SVGElement) {
9051                         this.dom.className.baseVal = cn.replace(re, " ");
9052                     } else {
9053                         this.dom.className = cn.replace(re, " ");
9054                     }
9055                 }
9056             }
9057             return this;
9058         },
9059
9060         // private
9061         classReCache: {},
9062
9063         /**
9064          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9065          * @param {String} className The CSS class to toggle
9066          * @return {Roo.Element} this
9067          */
9068         toggleClass : function(className){
9069             if(this.hasClass(className)){
9070                 this.removeClass(className);
9071             }else{
9072                 this.addClass(className);
9073             }
9074             return this;
9075         },
9076
9077         /**
9078          * Checks if the specified CSS class exists on this element's DOM node.
9079          * @param {String} className The CSS class to check for
9080          * @return {Boolean} True if the class exists, else false
9081          */
9082         hasClass : function(className){
9083             if (this.dom instanceof SVGElement) {
9084                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
9085             } 
9086             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9087         },
9088
9089         /**
9090          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
9091          * @param {String} oldClassName The CSS class to replace
9092          * @param {String} newClassName The replacement CSS class
9093          * @return {Roo.Element} this
9094          */
9095         replaceClass : function(oldClassName, newClassName){
9096             this.removeClass(oldClassName);
9097             this.addClass(newClassName);
9098             return this;
9099         },
9100
9101         /**
9102          * Returns an object with properties matching the styles requested.
9103          * For example, el.getStyles('color', 'font-size', 'width') might return
9104          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9105          * @param {String} style1 A style name
9106          * @param {String} style2 A style name
9107          * @param {String} etc.
9108          * @return {Object} The style object
9109          */
9110         getStyles : function(){
9111             var a = arguments, len = a.length, r = {};
9112             for(var i = 0; i < len; i++){
9113                 r[a[i]] = this.getStyle(a[i]);
9114             }
9115             return r;
9116         },
9117
9118         /**
9119          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9120          * @param {String} property The style property whose value is returned.
9121          * @return {String} The current value of the style property for this element.
9122          */
9123         getStyle : function(){
9124             return view && view.getComputedStyle ?
9125                 function(prop){
9126                     var el = this.dom, v, cs, camel;
9127                     if(prop == 'float'){
9128                         prop = "cssFloat";
9129                     }
9130                     if(el.style && (v = el.style[prop])){
9131                         return v;
9132                     }
9133                     if(cs = view.getComputedStyle(el, "")){
9134                         if(!(camel = propCache[prop])){
9135                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
9136                         }
9137                         return cs[camel];
9138                     }
9139                     return null;
9140                 } :
9141                 function(prop){
9142                     var el = this.dom, v, cs, camel;
9143                     if(prop == 'opacity'){
9144                         if(typeof el.style.filter == 'string'){
9145                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9146                             if(m){
9147                                 var fv = parseFloat(m[1]);
9148                                 if(!isNaN(fv)){
9149                                     return fv ? fv / 100 : 0;
9150                                 }
9151                             }
9152                         }
9153                         return 1;
9154                     }else if(prop == 'float'){
9155                         prop = "styleFloat";
9156                     }
9157                     if(!(camel = propCache[prop])){
9158                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
9159                     }
9160                     if(v = el.style[camel]){
9161                         return v;
9162                     }
9163                     if(cs = el.currentStyle){
9164                         return cs[camel];
9165                     }
9166                     return null;
9167                 };
9168         }(),
9169
9170         /**
9171          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9172          * @param {String/Object} property The style property to be set, or an object of multiple styles.
9173          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9174          * @return {Roo.Element} this
9175          */
9176         setStyle : function(prop, value){
9177             if(typeof prop == "string"){
9178                 
9179                 if (prop == 'float') {
9180                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9181                     return this;
9182                 }
9183                 
9184                 var camel;
9185                 if(!(camel = propCache[prop])){
9186                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9187                 }
9188                 
9189                 if(camel == 'opacity') {
9190                     this.setOpacity(value);
9191                 }else{
9192                     this.dom.style[camel] = value;
9193                 }
9194             }else{
9195                 for(var style in prop){
9196                     if(typeof prop[style] != "function"){
9197                        this.setStyle(style, prop[style]);
9198                     }
9199                 }
9200             }
9201             return this;
9202         },
9203
9204         /**
9205          * More flexible version of {@link #setStyle} for setting style properties.
9206          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9207          * a function which returns such a specification.
9208          * @return {Roo.Element} this
9209          */
9210         applyStyles : function(style){
9211             Roo.DomHelper.applyStyles(this.dom, style);
9212             return this;
9213         },
9214
9215         /**
9216           * 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).
9217           * @return {Number} The X position of the element
9218           */
9219         getX : function(){
9220             return D.getX(this.dom);
9221         },
9222
9223         /**
9224           * 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).
9225           * @return {Number} The Y position of the element
9226           */
9227         getY : function(){
9228             return D.getY(this.dom);
9229         },
9230
9231         /**
9232           * 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).
9233           * @return {Array} The XY position of the element
9234           */
9235         getXY : function(){
9236             return D.getXY(this.dom);
9237         },
9238
9239         /**
9240          * 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).
9241          * @param {Number} The X position of the element
9242          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9243          * @return {Roo.Element} this
9244          */
9245         setX : function(x, animate){
9246             if(!animate || !A){
9247                 D.setX(this.dom, x);
9248             }else{
9249                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9250             }
9251             return this;
9252         },
9253
9254         /**
9255          * 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).
9256          * @param {Number} The Y position of the element
9257          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9258          * @return {Roo.Element} this
9259          */
9260         setY : function(y, animate){
9261             if(!animate || !A){
9262                 D.setY(this.dom, y);
9263             }else{
9264                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9265             }
9266             return this;
9267         },
9268
9269         /**
9270          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9271          * @param {String} left The left CSS property value
9272          * @return {Roo.Element} this
9273          */
9274         setLeft : function(left){
9275             this.setStyle("left", this.addUnits(left));
9276             return this;
9277         },
9278
9279         /**
9280          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9281          * @param {String} top The top CSS property value
9282          * @return {Roo.Element} this
9283          */
9284         setTop : function(top){
9285             this.setStyle("top", this.addUnits(top));
9286             return this;
9287         },
9288
9289         /**
9290          * Sets the element's CSS right style.
9291          * @param {String} right The right CSS property value
9292          * @return {Roo.Element} this
9293          */
9294         setRight : function(right){
9295             this.setStyle("right", this.addUnits(right));
9296             return this;
9297         },
9298
9299         /**
9300          * Sets the element's CSS bottom style.
9301          * @param {String} bottom The bottom CSS property value
9302          * @return {Roo.Element} this
9303          */
9304         setBottom : function(bottom){
9305             this.setStyle("bottom", this.addUnits(bottom));
9306             return this;
9307         },
9308
9309         /**
9310          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9311          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9312          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9313          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9314          * @return {Roo.Element} this
9315          */
9316         setXY : function(pos, animate){
9317             if(!animate || !A){
9318                 D.setXY(this.dom, pos);
9319             }else{
9320                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9321             }
9322             return this;
9323         },
9324
9325         /**
9326          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9327          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9328          * @param {Number} x X value for new position (coordinates are page-based)
9329          * @param {Number} y Y value for new position (coordinates are page-based)
9330          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9331          * @return {Roo.Element} this
9332          */
9333         setLocation : function(x, y, animate){
9334             this.setXY([x, y], this.preanim(arguments, 2));
9335             return this;
9336         },
9337
9338         /**
9339          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9340          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9341          * @param {Number} x X value for new position (coordinates are page-based)
9342          * @param {Number} y Y value for new position (coordinates are page-based)
9343          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9344          * @return {Roo.Element} this
9345          */
9346         moveTo : function(x, y, animate){
9347             this.setXY([x, y], this.preanim(arguments, 2));
9348             return this;
9349         },
9350
9351         /**
9352          * Returns the region of the given element.
9353          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9354          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9355          */
9356         getRegion : function(){
9357             return D.getRegion(this.dom);
9358         },
9359
9360         /**
9361          * Returns the offset height of the element
9362          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9363          * @return {Number} The element's height
9364          */
9365         getHeight : function(contentHeight){
9366             var h = this.dom.offsetHeight || 0;
9367             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9368         },
9369
9370         /**
9371          * Returns the offset width of the element
9372          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9373          * @return {Number} The element's width
9374          */
9375         getWidth : function(contentWidth){
9376             var w = this.dom.offsetWidth || 0;
9377             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9378         },
9379
9380         /**
9381          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9382          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9383          * if a height has not been set using CSS.
9384          * @return {Number}
9385          */
9386         getComputedHeight : function(){
9387             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9388             if(!h){
9389                 h = parseInt(this.getStyle('height'), 10) || 0;
9390                 if(!this.isBorderBox()){
9391                     h += this.getFrameWidth('tb');
9392                 }
9393             }
9394             return h;
9395         },
9396
9397         /**
9398          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9399          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9400          * if a width has not been set using CSS.
9401          * @return {Number}
9402          */
9403         getComputedWidth : function(){
9404             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9405             if(!w){
9406                 w = parseInt(this.getStyle('width'), 10) || 0;
9407                 if(!this.isBorderBox()){
9408                     w += this.getFrameWidth('lr');
9409                 }
9410             }
9411             return w;
9412         },
9413
9414         /**
9415          * Returns the size of the element.
9416          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9417          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9418          */
9419         getSize : function(contentSize){
9420             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9421         },
9422
9423         /**
9424          * Returns the width and height of the viewport.
9425          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9426          */
9427         getViewSize : function(){
9428             var d = this.dom, doc = document, aw = 0, ah = 0;
9429             if(d == doc || d == doc.body){
9430                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9431             }else{
9432                 return {
9433                     width : d.clientWidth,
9434                     height: d.clientHeight
9435                 };
9436             }
9437         },
9438
9439         /**
9440          * Returns the value of the "value" attribute
9441          * @param {Boolean} asNumber true to parse the value as a number
9442          * @return {String/Number}
9443          */
9444         getValue : function(asNumber){
9445             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9446         },
9447
9448         // private
9449         adjustWidth : function(width){
9450             if(typeof width == "number"){
9451                 if(this.autoBoxAdjust && !this.isBorderBox()){
9452                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9453                 }
9454                 if(width < 0){
9455                     width = 0;
9456                 }
9457             }
9458             return width;
9459         },
9460
9461         // private
9462         adjustHeight : function(height){
9463             if(typeof height == "number"){
9464                if(this.autoBoxAdjust && !this.isBorderBox()){
9465                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9466                }
9467                if(height < 0){
9468                    height = 0;
9469                }
9470             }
9471             return height;
9472         },
9473
9474         /**
9475          * Set the width of the element
9476          * @param {Number} width The new width
9477          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9478          * @return {Roo.Element} this
9479          */
9480         setWidth : function(width, animate){
9481             width = this.adjustWidth(width);
9482             if(!animate || !A){
9483                 this.dom.style.width = this.addUnits(width);
9484             }else{
9485                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9486             }
9487             return this;
9488         },
9489
9490         /**
9491          * Set the height of the element
9492          * @param {Number} height The new height
9493          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9494          * @return {Roo.Element} this
9495          */
9496          setHeight : function(height, animate){
9497             height = this.adjustHeight(height);
9498             if(!animate || !A){
9499                 this.dom.style.height = this.addUnits(height);
9500             }else{
9501                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9502             }
9503             return this;
9504         },
9505
9506         /**
9507          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9508          * @param {Number} width The new width
9509          * @param {Number} height The new height
9510          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9511          * @return {Roo.Element} this
9512          */
9513          setSize : function(width, height, animate){
9514             if(typeof width == "object"){ // in case of object from getSize()
9515                 height = width.height; width = width.width;
9516             }
9517             width = this.adjustWidth(width); height = this.adjustHeight(height);
9518             if(!animate || !A){
9519                 this.dom.style.width = this.addUnits(width);
9520                 this.dom.style.height = this.addUnits(height);
9521             }else{
9522                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9523             }
9524             return this;
9525         },
9526
9527         /**
9528          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9529          * @param {Number} x X value for new position (coordinates are page-based)
9530          * @param {Number} y Y value for new position (coordinates are page-based)
9531          * @param {Number} width The new width
9532          * @param {Number} height The new height
9533          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9534          * @return {Roo.Element} this
9535          */
9536         setBounds : function(x, y, width, height, animate){
9537             if(!animate || !A){
9538                 this.setSize(width, height);
9539                 this.setLocation(x, y);
9540             }else{
9541                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9542                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9543                               this.preanim(arguments, 4), 'motion');
9544             }
9545             return this;
9546         },
9547
9548         /**
9549          * 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.
9550          * @param {Roo.lib.Region} region The region to fill
9551          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9552          * @return {Roo.Element} this
9553          */
9554         setRegion : function(region, animate){
9555             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9556             return this;
9557         },
9558
9559         /**
9560          * Appends an event handler
9561          *
9562          * @param {String}   eventName     The type of event to append
9563          * @param {Function} fn        The method the event invokes
9564          * @param {Object} scope       (optional) The scope (this object) of the fn
9565          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9566          */
9567         addListener : function(eventName, fn, scope, options)
9568         {
9569             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9570                 this.addListener('touchstart', this.onTapHandler, this);
9571             }
9572             
9573             // we need to handle a special case where dom element is a svg element.
9574             // in this case we do not actua
9575             if (!this.dom) {
9576                 return;
9577             }
9578             
9579             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9580                 if (typeof(this.listeners[eventName]) == 'undefined') {
9581                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9582                 }
9583                 this.listeners[eventName].addListener(fn, scope, options);
9584                 return;
9585             }
9586             
9587                 
9588             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9589             
9590             
9591         },
9592         tapedTwice : false,
9593         onTapHandler : function(event)
9594         {
9595             if(!this.tapedTwice) {
9596                 this.tapedTwice = true;
9597                 var s = this;
9598                 setTimeout( function() {
9599                     s.tapedTwice = false;
9600                 }, 300 );
9601                 return;
9602             }
9603             event.preventDefault();
9604             var revent = new MouseEvent('dblclick',  {
9605                 view: window,
9606                 bubbles: true,
9607                 cancelable: true
9608             });
9609              
9610             this.dom.dispatchEvent(revent);
9611             //action on double tap goes below
9612              
9613         }, 
9614  
9615         /**
9616          * Removes an event handler from this element
9617          * @param {String} eventName the type of event to remove
9618          * @param {Function} fn the method the event invokes
9619          * @param {Function} scope (needed for svg fake listeners)
9620          * @return {Roo.Element} this
9621          */
9622         removeListener : function(eventName, fn, scope){
9623             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9624             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9625                 return this;
9626             }
9627             this.listeners[eventName].removeListener(fn, scope);
9628             return this;
9629         },
9630
9631         /**
9632          * Removes all previous added listeners from this element
9633          * @return {Roo.Element} this
9634          */
9635         removeAllListeners : function(){
9636             E.purgeElement(this.dom);
9637             this.listeners = {};
9638             return this;
9639         },
9640
9641         relayEvent : function(eventName, observable){
9642             this.on(eventName, function(e){
9643                 observable.fireEvent(eventName, e);
9644             });
9645         },
9646
9647         
9648         /**
9649          * Set the opacity of the element
9650          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9651          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9652          * @return {Roo.Element} this
9653          */
9654          setOpacity : function(opacity, animate){
9655             if(!animate || !A){
9656                 var s = this.dom.style;
9657                 if(Roo.isIE){
9658                     s.zoom = 1;
9659                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9660                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9661                 }else{
9662                     s.opacity = opacity;
9663                 }
9664             }else{
9665                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9666             }
9667             return this;
9668         },
9669
9670         /**
9671          * Gets the left X coordinate
9672          * @param {Boolean} local True to get the local css position instead of page coordinate
9673          * @return {Number}
9674          */
9675         getLeft : function(local){
9676             if(!local){
9677                 return this.getX();
9678             }else{
9679                 return parseInt(this.getStyle("left"), 10) || 0;
9680             }
9681         },
9682
9683         /**
9684          * Gets the right X coordinate of the element (element X position + element width)
9685          * @param {Boolean} local True to get the local css position instead of page coordinate
9686          * @return {Number}
9687          */
9688         getRight : function(local){
9689             if(!local){
9690                 return this.getX() + this.getWidth();
9691             }else{
9692                 return (this.getLeft(true) + this.getWidth()) || 0;
9693             }
9694         },
9695
9696         /**
9697          * Gets the top Y coordinate
9698          * @param {Boolean} local True to get the local css position instead of page coordinate
9699          * @return {Number}
9700          */
9701         getTop : function(local) {
9702             if(!local){
9703                 return this.getY();
9704             }else{
9705                 return parseInt(this.getStyle("top"), 10) || 0;
9706             }
9707         },
9708
9709         /**
9710          * Gets the bottom Y coordinate of the element (element Y position + element height)
9711          * @param {Boolean} local True to get the local css position instead of page coordinate
9712          * @return {Number}
9713          */
9714         getBottom : function(local){
9715             if(!local){
9716                 return this.getY() + this.getHeight();
9717             }else{
9718                 return (this.getTop(true) + this.getHeight()) || 0;
9719             }
9720         },
9721
9722         /**
9723         * Initializes positioning on this element. If a desired position is not passed, it will make the
9724         * the element positioned relative IF it is not already positioned.
9725         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9726         * @param {Number} zIndex (optional) The zIndex to apply
9727         * @param {Number} x (optional) Set the page X position
9728         * @param {Number} y (optional) Set the page Y position
9729         */
9730         position : function(pos, zIndex, x, y){
9731             if(!pos){
9732                if(this.getStyle('position') == 'static'){
9733                    this.setStyle('position', 'relative');
9734                }
9735             }else{
9736                 this.setStyle("position", pos);
9737             }
9738             if(zIndex){
9739                 this.setStyle("z-index", zIndex);
9740             }
9741             if(x !== undefined && y !== undefined){
9742                 this.setXY([x, y]);
9743             }else if(x !== undefined){
9744                 this.setX(x);
9745             }else if(y !== undefined){
9746                 this.setY(y);
9747             }
9748         },
9749
9750         /**
9751         * Clear positioning back to the default when the document was loaded
9752         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9753         * @return {Roo.Element} this
9754          */
9755         clearPositioning : function(value){
9756             value = value ||'';
9757             this.setStyle({
9758                 "left": value,
9759                 "right": value,
9760                 "top": value,
9761                 "bottom": value,
9762                 "z-index": "",
9763                 "position" : "static"
9764             });
9765             return this;
9766         },
9767
9768         /**
9769         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9770         * snapshot before performing an update and then restoring the element.
9771         * @return {Object}
9772         */
9773         getPositioning : function(){
9774             var l = this.getStyle("left");
9775             var t = this.getStyle("top");
9776             return {
9777                 "position" : this.getStyle("position"),
9778                 "left" : l,
9779                 "right" : l ? "" : this.getStyle("right"),
9780                 "top" : t,
9781                 "bottom" : t ? "" : this.getStyle("bottom"),
9782                 "z-index" : this.getStyle("z-index")
9783             };
9784         },
9785
9786         /**
9787          * Gets the width of the border(s) for the specified side(s)
9788          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9789          * passing lr would get the border (l)eft width + the border (r)ight width.
9790          * @return {Number} The width of the sides passed added together
9791          */
9792         getBorderWidth : function(side){
9793             return this.addStyles(side, El.borders);
9794         },
9795
9796         /**
9797          * Gets the width of the padding(s) for the specified side(s)
9798          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9799          * passing lr would get the padding (l)eft + the padding (r)ight.
9800          * @return {Number} The padding of the sides passed added together
9801          */
9802         getPadding : function(side){
9803             return this.addStyles(side, El.paddings);
9804         },
9805
9806         /**
9807         * Set positioning with an object returned by getPositioning().
9808         * @param {Object} posCfg
9809         * @return {Roo.Element} this
9810          */
9811         setPositioning : function(pc){
9812             this.applyStyles(pc);
9813             if(pc.right == "auto"){
9814                 this.dom.style.right = "";
9815             }
9816             if(pc.bottom == "auto"){
9817                 this.dom.style.bottom = "";
9818             }
9819             return this;
9820         },
9821
9822         // private
9823         fixDisplay : function(){
9824             if(this.getStyle("display") == "none"){
9825                 this.setStyle("visibility", "hidden");
9826                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9827                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9828                     this.setStyle("display", "block");
9829                 }
9830             }
9831         },
9832
9833         /**
9834          * Quick set left and top adding default units
9835          * @param {String} left The left CSS property value
9836          * @param {String} top The top CSS property value
9837          * @return {Roo.Element} this
9838          */
9839          setLeftTop : function(left, top){
9840             this.dom.style.left = this.addUnits(left);
9841             this.dom.style.top = this.addUnits(top);
9842             return this;
9843         },
9844
9845         /**
9846          * Move this element relative to its current position.
9847          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9848          * @param {Number} distance How far to move the element in pixels
9849          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9850          * @return {Roo.Element} this
9851          */
9852          move : function(direction, distance, animate){
9853             var xy = this.getXY();
9854             direction = direction.toLowerCase();
9855             switch(direction){
9856                 case "l":
9857                 case "left":
9858                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9859                     break;
9860                case "r":
9861                case "right":
9862                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9863                     break;
9864                case "t":
9865                case "top":
9866                case "up":
9867                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9868                     break;
9869                case "b":
9870                case "bottom":
9871                case "down":
9872                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9873                     break;
9874             }
9875             return this;
9876         },
9877
9878         /**
9879          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9880          * @return {Roo.Element} this
9881          */
9882         clip : function(){
9883             if(!this.isClipped){
9884                this.isClipped = true;
9885                this.originalClip = {
9886                    "o": this.getStyle("overflow"),
9887                    "x": this.getStyle("overflow-x"),
9888                    "y": this.getStyle("overflow-y")
9889                };
9890                this.setStyle("overflow", "hidden");
9891                this.setStyle("overflow-x", "hidden");
9892                this.setStyle("overflow-y", "hidden");
9893             }
9894             return this;
9895         },
9896
9897         /**
9898          *  Return clipping (overflow) to original clipping before clip() was called
9899          * @return {Roo.Element} this
9900          */
9901         unclip : function(){
9902             if(this.isClipped){
9903                 this.isClipped = false;
9904                 var o = this.originalClip;
9905                 if(o.o){this.setStyle("overflow", o.o);}
9906                 if(o.x){this.setStyle("overflow-x", o.x);}
9907                 if(o.y){this.setStyle("overflow-y", o.y);}
9908             }
9909             return this;
9910         },
9911
9912
9913         /**
9914          * Gets the x,y coordinates specified by the anchor position on the element.
9915          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9916          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9917          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9918          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9919          * @return {Array} [x, y] An array containing the element's x and y coordinates
9920          */
9921         getAnchorXY : function(anchor, local, s){
9922             //Passing a different size is useful for pre-calculating anchors,
9923             //especially for anchored animations that change the el size.
9924
9925             var w, h, vp = false;
9926             if(!s){
9927                 var d = this.dom;
9928                 if(d == document.body || d == document){
9929                     vp = true;
9930                     w = D.getViewWidth(); h = D.getViewHeight();
9931                 }else{
9932                     w = this.getWidth(); h = this.getHeight();
9933                 }
9934             }else{
9935                 w = s.width;  h = s.height;
9936             }
9937             var x = 0, y = 0, r = Math.round;
9938             switch((anchor || "tl").toLowerCase()){
9939                 case "c":
9940                     x = r(w*.5);
9941                     y = r(h*.5);
9942                 break;
9943                 case "t":
9944                     x = r(w*.5);
9945                     y = 0;
9946                 break;
9947                 case "l":
9948                     x = 0;
9949                     y = r(h*.5);
9950                 break;
9951                 case "r":
9952                     x = w;
9953                     y = r(h*.5);
9954                 break;
9955                 case "b":
9956                     x = r(w*.5);
9957                     y = h;
9958                 break;
9959                 case "tl":
9960                     x = 0;
9961                     y = 0;
9962                 break;
9963                 case "bl":
9964                     x = 0;
9965                     y = h;
9966                 break;
9967                 case "br":
9968                     x = w;
9969                     y = h;
9970                 break;
9971                 case "tr":
9972                     x = w;
9973                     y = 0;
9974                 break;
9975             }
9976             if(local === true){
9977                 return [x, y];
9978             }
9979             if(vp){
9980                 var sc = this.getScroll();
9981                 return [x + sc.left, y + sc.top];
9982             }
9983             //Add the element's offset xy
9984             var o = this.getXY();
9985             return [x+o[0], y+o[1]];
9986         },
9987
9988         /**
9989          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9990          * supported position values.
9991          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9992          * @param {String} position The position to align to.
9993          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9994          * @return {Array} [x, y]
9995          */
9996         getAlignToXY : function(el, p, o)
9997         {
9998             el = Roo.get(el);
9999             var d = this.dom;
10000             if(!el.dom){
10001                 throw "Element.alignTo with an element that doesn't exist";
10002             }
10003             var c = false; //constrain to viewport
10004             var p1 = "", p2 = "";
10005             o = o || [0,0];
10006
10007             if(!p){
10008                 p = "tl-bl";
10009             }else if(p == "?"){
10010                 p = "tl-bl?";
10011             }else if(p.indexOf("-") == -1){
10012                 p = "tl-" + p;
10013             }
10014             p = p.toLowerCase();
10015             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10016             if(!m){
10017                throw "Element.alignTo with an invalid alignment " + p;
10018             }
10019             p1 = m[1]; p2 = m[2]; c = !!m[3];
10020
10021             //Subtract the aligned el's internal xy from the target's offset xy
10022             //plus custom offset to get the aligned el's new offset xy
10023             var a1 = this.getAnchorXY(p1, true);
10024             var a2 = el.getAnchorXY(p2, false);
10025             var x = a2[0] - a1[0] + o[0];
10026             var y = a2[1] - a1[1] + o[1];
10027             if(c){
10028                 //constrain the aligned el to viewport if necessary
10029                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10030                 // 5px of margin for ie
10031                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10032
10033                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10034                 //perpendicular to the vp border, allow the aligned el to slide on that border,
10035                 //otherwise swap the aligned el to the opposite border of the target.
10036                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10037                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10038                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
10039                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10040
10041                var doc = document;
10042                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10043                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10044
10045                if((x+w) > dw + scrollX){
10046                     x = swapX ? r.left-w : dw+scrollX-w;
10047                 }
10048                if(x < scrollX){
10049                    x = swapX ? r.right : scrollX;
10050                }
10051                if((y+h) > dh + scrollY){
10052                     y = swapY ? r.top-h : dh+scrollY-h;
10053                 }
10054                if (y < scrollY){
10055                    y = swapY ? r.bottom : scrollY;
10056                }
10057             }
10058             return [x,y];
10059         },
10060
10061         // private
10062         getConstrainToXY : function(){
10063             var os = {top:0, left:0, bottom:0, right: 0};
10064
10065             return function(el, local, offsets, proposedXY){
10066                 el = Roo.get(el);
10067                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10068
10069                 var vw, vh, vx = 0, vy = 0;
10070                 if(el.dom == document.body || el.dom == document){
10071                     vw = Roo.lib.Dom.getViewWidth();
10072                     vh = Roo.lib.Dom.getViewHeight();
10073                 }else{
10074                     vw = el.dom.clientWidth;
10075                     vh = el.dom.clientHeight;
10076                     if(!local){
10077                         var vxy = el.getXY();
10078                         vx = vxy[0];
10079                         vy = vxy[1];
10080                     }
10081                 }
10082
10083                 var s = el.getScroll();
10084
10085                 vx += offsets.left + s.left;
10086                 vy += offsets.top + s.top;
10087
10088                 vw -= offsets.right;
10089                 vh -= offsets.bottom;
10090
10091                 var vr = vx+vw;
10092                 var vb = vy+vh;
10093
10094                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10095                 var x = xy[0], y = xy[1];
10096                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10097
10098                 // only move it if it needs it
10099                 var moved = false;
10100
10101                 // first validate right/bottom
10102                 if((x + w) > vr){
10103                     x = vr - w;
10104                     moved = true;
10105                 }
10106                 if((y + h) > vb){
10107                     y = vb - h;
10108                     moved = true;
10109                 }
10110                 // then make sure top/left isn't negative
10111                 if(x < vx){
10112                     x = vx;
10113                     moved = true;
10114                 }
10115                 if(y < vy){
10116                     y = vy;
10117                     moved = true;
10118                 }
10119                 return moved ? [x, y] : false;
10120             };
10121         }(),
10122
10123         // private
10124         adjustForConstraints : function(xy, parent, offsets){
10125             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
10126         },
10127
10128         /**
10129          * Aligns this element with another element relative to the specified anchor points. If the other element is the
10130          * document it aligns it to the viewport.
10131          * The position parameter is optional, and can be specified in any one of the following formats:
10132          * <ul>
10133          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10134          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10135          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
10136          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
10137          *   <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
10138          *       element's anchor point, and the second value is used as the target's anchor point.</li>
10139          * </ul>
10140          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
10141          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10142          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
10143          * that specified in order to enforce the viewport constraints.
10144          * Following are all of the supported anchor positions:
10145     <pre>
10146     Value  Description
10147     -----  -----------------------------
10148     tl     The top left corner (default)
10149     t      The center of the top edge
10150     tr     The top right corner
10151     l      The center of the left edge
10152     c      In the center of the element
10153     r      The center of the right edge
10154     bl     The bottom left corner
10155     b      The center of the bottom edge
10156     br     The bottom right corner
10157     </pre>
10158     Example Usage:
10159     <pre><code>
10160     // align el to other-el using the default positioning ("tl-bl", non-constrained)
10161     el.alignTo("other-el");
10162
10163     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10164     el.alignTo("other-el", "tr?");
10165
10166     // align the bottom right corner of el with the center left edge of other-el
10167     el.alignTo("other-el", "br-l?");
10168
10169     // align the center of el with the bottom left corner of other-el and
10170     // adjust the x position by -6 pixels (and the y position by 0)
10171     el.alignTo("other-el", "c-bl", [-6, 0]);
10172     </code></pre>
10173          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10174          * @param {String} position The position to align to.
10175          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10176          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10177          * @return {Roo.Element} this
10178          */
10179         alignTo : function(element, position, offsets, animate){
10180             var xy = this.getAlignToXY(element, position, offsets);
10181             this.setXY(xy, this.preanim(arguments, 3));
10182             return this;
10183         },
10184
10185         /**
10186          * Anchors an element to another element and realigns it when the window is resized.
10187          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10188          * @param {String} position The position to align to.
10189          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10190          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10191          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10192          * is a number, it is used as the buffer delay (defaults to 50ms).
10193          * @param {Function} callback The function to call after the animation finishes
10194          * @return {Roo.Element} this
10195          */
10196         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10197             var action = function(){
10198                 this.alignTo(el, alignment, offsets, animate);
10199                 Roo.callback(callback, this);
10200             };
10201             Roo.EventManager.onWindowResize(action, this);
10202             var tm = typeof monitorScroll;
10203             if(tm != 'undefined'){
10204                 Roo.EventManager.on(window, 'scroll', action, this,
10205                     {buffer: tm == 'number' ? monitorScroll : 50});
10206             }
10207             action.call(this); // align immediately
10208             return this;
10209         },
10210         /**
10211          * Clears any opacity settings from this element. Required in some cases for IE.
10212          * @return {Roo.Element} this
10213          */
10214         clearOpacity : function(){
10215             if (window.ActiveXObject) {
10216                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10217                     this.dom.style.filter = "";
10218                 }
10219             } else {
10220                 this.dom.style.opacity = "";
10221                 this.dom.style["-moz-opacity"] = "";
10222                 this.dom.style["-khtml-opacity"] = "";
10223             }
10224             return this;
10225         },
10226
10227         /**
10228          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10229          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10230          * @return {Roo.Element} this
10231          */
10232         hide : function(animate){
10233             this.setVisible(false, this.preanim(arguments, 0));
10234             return this;
10235         },
10236
10237         /**
10238         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10239         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10240          * @return {Roo.Element} this
10241          */
10242         show : function(animate){
10243             this.setVisible(true, this.preanim(arguments, 0));
10244             return this;
10245         },
10246
10247         /**
10248          * @private Test if size has a unit, otherwise appends the default
10249          */
10250         addUnits : function(size){
10251             return Roo.Element.addUnits(size, this.defaultUnit);
10252         },
10253
10254         /**
10255          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10256          * @return {Roo.Element} this
10257          */
10258         beginMeasure : function(){
10259             var el = this.dom;
10260             if(el.offsetWidth || el.offsetHeight){
10261                 return this; // offsets work already
10262             }
10263             var changed = [];
10264             var p = this.dom, b = document.body; // start with this element
10265             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10266                 var pe = Roo.get(p);
10267                 if(pe.getStyle('display') == 'none'){
10268                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10269                     p.style.visibility = "hidden";
10270                     p.style.display = "block";
10271                 }
10272                 p = p.parentNode;
10273             }
10274             this._measureChanged = changed;
10275             return this;
10276
10277         },
10278
10279         /**
10280          * Restores displays to before beginMeasure was called
10281          * @return {Roo.Element} this
10282          */
10283         endMeasure : function(){
10284             var changed = this._measureChanged;
10285             if(changed){
10286                 for(var i = 0, len = changed.length; i < len; i++) {
10287                     var r = changed[i];
10288                     r.el.style.visibility = r.visibility;
10289                     r.el.style.display = "none";
10290                 }
10291                 this._measureChanged = null;
10292             }
10293             return this;
10294         },
10295
10296         /**
10297         * Update the innerHTML of this element, optionally searching for and processing scripts
10298         * @param {String} html The new HTML
10299         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10300         * @param {Function} callback For async script loading you can be noticed when the update completes
10301         * @return {Roo.Element} this
10302          */
10303         update : function(html, loadScripts, callback){
10304             if(typeof html == "undefined"){
10305                 html = "";
10306             }
10307             if(loadScripts !== true){
10308                 this.dom.innerHTML = html;
10309                 if(typeof callback == "function"){
10310                     callback();
10311                 }
10312                 return this;
10313             }
10314             var id = Roo.id();
10315             var dom = this.dom;
10316
10317             html += '<span id="' + id + '"></span>';
10318
10319             E.onAvailable(id, function(){
10320                 var hd = document.getElementsByTagName("head")[0];
10321                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10322                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10323                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10324
10325                 var match;
10326                 while(match = re.exec(html)){
10327                     var attrs = match[1];
10328                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10329                     if(srcMatch && srcMatch[2]){
10330                        var s = document.createElement("script");
10331                        s.src = srcMatch[2];
10332                        var typeMatch = attrs.match(typeRe);
10333                        if(typeMatch && typeMatch[2]){
10334                            s.type = typeMatch[2];
10335                        }
10336                        hd.appendChild(s);
10337                     }else if(match[2] && match[2].length > 0){
10338                         if(window.execScript) {
10339                            window.execScript(match[2]);
10340                         } else {
10341                             /**
10342                              * eval:var:id
10343                              * eval:var:dom
10344                              * eval:var:html
10345                              * 
10346                              */
10347                            window.eval(match[2]);
10348                         }
10349                     }
10350                 }
10351                 var el = document.getElementById(id);
10352                 if(el){el.parentNode.removeChild(el);}
10353                 if(typeof callback == "function"){
10354                     callback();
10355                 }
10356             });
10357             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10358             return this;
10359         },
10360
10361         /**
10362          * Direct access to the UpdateManager update() method (takes the same parameters).
10363          * @param {String/Function} url The url for this request or a function to call to get the url
10364          * @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}
10365          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10366          * @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.
10367          * @return {Roo.Element} this
10368          */
10369         load : function(){
10370             var um = this.getUpdateManager();
10371             um.update.apply(um, arguments);
10372             return this;
10373         },
10374
10375         /**
10376         * Gets this element's UpdateManager
10377         * @return {Roo.UpdateManager} The UpdateManager
10378         */
10379         getUpdateManager : function(){
10380             if(!this.updateManager){
10381                 this.updateManager = new Roo.UpdateManager(this);
10382             }
10383             return this.updateManager;
10384         },
10385
10386         /**
10387          * Disables text selection for this element (normalized across browsers)
10388          * @return {Roo.Element} this
10389          */
10390         unselectable : function(){
10391             this.dom.unselectable = "on";
10392             this.swallowEvent("selectstart", true);
10393             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10394             this.addClass("x-unselectable");
10395             return this;
10396         },
10397
10398         /**
10399         * Calculates the x, y to center this element on the screen
10400         * @return {Array} The x, y values [x, y]
10401         */
10402         getCenterXY : function(){
10403             return this.getAlignToXY(document, 'c-c');
10404         },
10405
10406         /**
10407         * Centers the Element in either the viewport, or another Element.
10408         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10409         */
10410         center : function(centerIn){
10411             this.alignTo(centerIn || document, 'c-c');
10412             return this;
10413         },
10414
10415         /**
10416          * Tests various css rules/browsers to determine if this element uses a border box
10417          * @return {Boolean}
10418          */
10419         isBorderBox : function(){
10420             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10421         },
10422
10423         /**
10424          * Return a box {x, y, width, height} that can be used to set another elements
10425          * size/location to match this element.
10426          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10427          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10428          * @return {Object} box An object in the format {x, y, width, height}
10429          */
10430         getBox : function(contentBox, local){
10431             var xy;
10432             if(!local){
10433                 xy = this.getXY();
10434             }else{
10435                 var left = parseInt(this.getStyle("left"), 10) || 0;
10436                 var top = parseInt(this.getStyle("top"), 10) || 0;
10437                 xy = [left, top];
10438             }
10439             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10440             if(!contentBox){
10441                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10442             }else{
10443                 var l = this.getBorderWidth("l")+this.getPadding("l");
10444                 var r = this.getBorderWidth("r")+this.getPadding("r");
10445                 var t = this.getBorderWidth("t")+this.getPadding("t");
10446                 var b = this.getBorderWidth("b")+this.getPadding("b");
10447                 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)};
10448             }
10449             bx.right = bx.x + bx.width;
10450             bx.bottom = bx.y + bx.height;
10451             return bx;
10452         },
10453
10454         /**
10455          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10456          for more information about the sides.
10457          * @param {String} sides
10458          * @return {Number}
10459          */
10460         getFrameWidth : function(sides, onlyContentBox){
10461             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10462         },
10463
10464         /**
10465          * 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.
10466          * @param {Object} box The box to fill {x, y, width, height}
10467          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10468          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10469          * @return {Roo.Element} this
10470          */
10471         setBox : function(box, adjust, animate){
10472             var w = box.width, h = box.height;
10473             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10474                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10475                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10476             }
10477             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10478             return this;
10479         },
10480
10481         /**
10482          * Forces the browser to repaint this element
10483          * @return {Roo.Element} this
10484          */
10485          repaint : function(){
10486             var dom = this.dom;
10487             this.addClass("x-repaint");
10488             setTimeout(function(){
10489                 Roo.get(dom).removeClass("x-repaint");
10490             }, 1);
10491             return this;
10492         },
10493
10494         /**
10495          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10496          * then it returns the calculated width of the sides (see getPadding)
10497          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10498          * @return {Object/Number}
10499          */
10500         getMargins : function(side){
10501             if(!side){
10502                 return {
10503                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10504                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10505                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10506                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10507                 };
10508             }else{
10509                 return this.addStyles(side, El.margins);
10510              }
10511         },
10512
10513         // private
10514         addStyles : function(sides, styles){
10515             var val = 0, v, w;
10516             for(var i = 0, len = sides.length; i < len; i++){
10517                 v = this.getStyle(styles[sides.charAt(i)]);
10518                 if(v){
10519                      w = parseInt(v, 10);
10520                      if(w){ val += w; }
10521                 }
10522             }
10523             return val;
10524         },
10525
10526         /**
10527          * Creates a proxy element of this element
10528          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10529          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10530          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10531          * @return {Roo.Element} The new proxy element
10532          */
10533         createProxy : function(config, renderTo, matchBox){
10534             if(renderTo){
10535                 renderTo = Roo.getDom(renderTo);
10536             }else{
10537                 renderTo = document.body;
10538             }
10539             config = typeof config == "object" ?
10540                 config : {tag : "div", cls: config};
10541             var proxy = Roo.DomHelper.append(renderTo, config, true);
10542             if(matchBox){
10543                proxy.setBox(this.getBox());
10544             }
10545             return proxy;
10546         },
10547
10548         /**
10549          * Puts a mask over this element to disable user interaction. Requires core.css.
10550          * This method can only be applied to elements which accept child nodes.
10551          * @param {String} msg (optional) A message to display in the mask
10552          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10553          * @return {Element} The mask  element
10554          */
10555         mask : function(msg, msgCls)
10556         {
10557             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10558                 this.setStyle("position", "relative");
10559             }
10560             if(!this._mask){
10561                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10562             }
10563             
10564             this.addClass("x-masked");
10565             this._mask.setDisplayed(true);
10566             
10567             // we wander
10568             var z = 0;
10569             var dom = this.dom;
10570             while (dom && dom.style) {
10571                 if (!isNaN(parseInt(dom.style.zIndex))) {
10572                     z = Math.max(z, parseInt(dom.style.zIndex));
10573                 }
10574                 dom = dom.parentNode;
10575             }
10576             // if we are masking the body - then it hides everything..
10577             if (this.dom == document.body) {
10578                 z = 1000000;
10579                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10580                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10581             }
10582            
10583             if(typeof msg == 'string'){
10584                 if(!this._maskMsg){
10585                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10586                         cls: "roo-el-mask-msg", 
10587                         cn: [
10588                             {
10589                                 tag: 'i',
10590                                 cls: 'fa fa-spinner fa-spin'
10591                             },
10592                             {
10593                                 tag: 'div'
10594                             }   
10595                         ]
10596                     }, true);
10597                 }
10598                 var mm = this._maskMsg;
10599                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10600                 if (mm.dom.lastChild) { // weird IE issue?
10601                     mm.dom.lastChild.innerHTML = msg;
10602                 }
10603                 mm.setDisplayed(true);
10604                 mm.center(this);
10605                 mm.setStyle('z-index', z + 102);
10606             }
10607             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10608                 this._mask.setHeight(this.getHeight());
10609             }
10610             this._mask.setStyle('z-index', z + 100);
10611             
10612             return this._mask;
10613         },
10614
10615         /**
10616          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10617          * it is cached for reuse.
10618          */
10619         unmask : function(removeEl){
10620             if(this._mask){
10621                 if(removeEl === true){
10622                     this._mask.remove();
10623                     delete this._mask;
10624                     if(this._maskMsg){
10625                         this._maskMsg.remove();
10626                         delete this._maskMsg;
10627                     }
10628                 }else{
10629                     this._mask.setDisplayed(false);
10630                     if(this._maskMsg){
10631                         this._maskMsg.setDisplayed(false);
10632                     }
10633                 }
10634             }
10635             this.removeClass("x-masked");
10636         },
10637
10638         /**
10639          * Returns true if this element is masked
10640          * @return {Boolean}
10641          */
10642         isMasked : function(){
10643             return this._mask && this._mask.isVisible();
10644         },
10645
10646         /**
10647          * Creates an iframe shim for this element to keep selects and other windowed objects from
10648          * showing through.
10649          * @return {Roo.Element} The new shim element
10650          */
10651         createShim : function(){
10652             var el = document.createElement('iframe');
10653             el.frameBorder = 'no';
10654             el.className = 'roo-shim';
10655             if(Roo.isIE && Roo.isSecure){
10656                 el.src = Roo.SSL_SECURE_URL;
10657             }
10658             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10659             shim.autoBoxAdjust = false;
10660             return shim;
10661         },
10662
10663         /**
10664          * Removes this element from the DOM and deletes it from the cache
10665          */
10666         remove : function(){
10667             if(this.dom.parentNode){
10668                 this.dom.parentNode.removeChild(this.dom);
10669             }
10670             delete El.cache[this.dom.id];
10671         },
10672
10673         /**
10674          * Sets up event handlers to add and remove a css class when the mouse is over this element
10675          * @param {String} className
10676          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10677          * mouseout events for children elements
10678          * @return {Roo.Element} this
10679          */
10680         addClassOnOver : function(className, preventFlicker){
10681             this.on("mouseover", function(){
10682                 Roo.fly(this, '_internal').addClass(className);
10683             }, this.dom);
10684             var removeFn = function(e){
10685                 if(preventFlicker !== true || !e.within(this, true)){
10686                     Roo.fly(this, '_internal').removeClass(className);
10687                 }
10688             };
10689             this.on("mouseout", removeFn, this.dom);
10690             return this;
10691         },
10692
10693         /**
10694          * Sets up event handlers to add and remove a css class when this element has the focus
10695          * @param {String} className
10696          * @return {Roo.Element} this
10697          */
10698         addClassOnFocus : function(className){
10699             this.on("focus", function(){
10700                 Roo.fly(this, '_internal').addClass(className);
10701             }, this.dom);
10702             this.on("blur", function(){
10703                 Roo.fly(this, '_internal').removeClass(className);
10704             }, this.dom);
10705             return this;
10706         },
10707         /**
10708          * 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)
10709          * @param {String} className
10710          * @return {Roo.Element} this
10711          */
10712         addClassOnClick : function(className){
10713             var dom = this.dom;
10714             this.on("mousedown", function(){
10715                 Roo.fly(dom, '_internal').addClass(className);
10716                 var d = Roo.get(document);
10717                 var fn = function(){
10718                     Roo.fly(dom, '_internal').removeClass(className);
10719                     d.removeListener("mouseup", fn);
10720                 };
10721                 d.on("mouseup", fn);
10722             });
10723             return this;
10724         },
10725
10726         /**
10727          * Stops the specified event from bubbling and optionally prevents the default action
10728          * @param {String} eventName
10729          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10730          * @return {Roo.Element} this
10731          */
10732         swallowEvent : function(eventName, preventDefault){
10733             var fn = function(e){
10734                 e.stopPropagation();
10735                 if(preventDefault){
10736                     e.preventDefault();
10737                 }
10738             };
10739             if(eventName instanceof Array){
10740                 for(var i = 0, len = eventName.length; i < len; i++){
10741                      this.on(eventName[i], fn);
10742                 }
10743                 return this;
10744             }
10745             this.on(eventName, fn);
10746             return this;
10747         },
10748
10749         /**
10750          * @private
10751          */
10752         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10753
10754         /**
10755          * Sizes this element to its parent element's dimensions performing
10756          * neccessary box adjustments.
10757          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10758          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10759          * @return {Roo.Element} this
10760          */
10761         fitToParent : function(monitorResize, targetParent) {
10762           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10763           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10764           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10765             return this;
10766           }
10767           var p = Roo.get(targetParent || this.dom.parentNode);
10768           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10769           if (monitorResize === true) {
10770             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10771             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10772           }
10773           return this;
10774         },
10775
10776         /**
10777          * Gets the next sibling, skipping text nodes
10778          * @return {HTMLElement} The next sibling or null
10779          */
10780         getNextSibling : function(){
10781             var n = this.dom.nextSibling;
10782             while(n && n.nodeType != 1){
10783                 n = n.nextSibling;
10784             }
10785             return n;
10786         },
10787
10788         /**
10789          * Gets the previous sibling, skipping text nodes
10790          * @return {HTMLElement} The previous sibling or null
10791          */
10792         getPrevSibling : function(){
10793             var n = this.dom.previousSibling;
10794             while(n && n.nodeType != 1){
10795                 n = n.previousSibling;
10796             }
10797             return n;
10798         },
10799
10800
10801         /**
10802          * Appends the passed element(s) to this element
10803          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10804          * @return {Roo.Element} this
10805          */
10806         appendChild: function(el){
10807             el = Roo.get(el);
10808             el.appendTo(this);
10809             return this;
10810         },
10811
10812         /**
10813          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10814          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10815          * automatically generated with the specified attributes.
10816          * @param {HTMLElement} insertBefore (optional) a child element of this element
10817          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10818          * @return {Roo.Element} The new child element
10819          */
10820         createChild: function(config, insertBefore, returnDom){
10821             config = config || {tag:'div'};
10822             if(insertBefore){
10823                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10824             }
10825             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10826         },
10827
10828         /**
10829          * Appends this element to the passed element
10830          * @param {String/HTMLElement/Element} el The new parent element
10831          * @return {Roo.Element} this
10832          */
10833         appendTo: function(el){
10834             el = Roo.getDom(el);
10835             el.appendChild(this.dom);
10836             return this;
10837         },
10838
10839         /**
10840          * Inserts this element before the passed element in the DOM
10841          * @param {String/HTMLElement/Element} el The element to insert before
10842          * @return {Roo.Element} this
10843          */
10844         insertBefore: function(el){
10845             el = Roo.getDom(el);
10846             el.parentNode.insertBefore(this.dom, el);
10847             return this;
10848         },
10849
10850         /**
10851          * Inserts this element after the passed element in the DOM
10852          * @param {String/HTMLElement/Element} el The element to insert after
10853          * @return {Roo.Element} this
10854          */
10855         insertAfter: function(el){
10856             el = Roo.getDom(el);
10857             el.parentNode.insertBefore(this.dom, el.nextSibling);
10858             return this;
10859         },
10860
10861         /**
10862          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10863          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10864          * @return {Roo.Element} The new child
10865          */
10866         insertFirst: function(el, returnDom){
10867             el = el || {};
10868             if(typeof el == 'object' && !el.nodeType){ // dh config
10869                 return this.createChild(el, this.dom.firstChild, returnDom);
10870             }else{
10871                 el = Roo.getDom(el);
10872                 this.dom.insertBefore(el, this.dom.firstChild);
10873                 return !returnDom ? Roo.get(el) : el;
10874             }
10875         },
10876
10877         /**
10878          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10879          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10880          * @param {String} where (optional) 'before' or 'after' defaults to before
10881          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10882          * @return {Roo.Element} the inserted Element
10883          */
10884         insertSibling: function(el, where, returnDom){
10885             where = where ? where.toLowerCase() : 'before';
10886             el = el || {};
10887             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10888
10889             if(typeof el == 'object' && !el.nodeType){ // dh config
10890                 if(where == 'after' && !this.dom.nextSibling){
10891                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10892                 }else{
10893                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10894                 }
10895
10896             }else{
10897                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10898                             where == 'before' ? this.dom : this.dom.nextSibling);
10899                 if(!returnDom){
10900                     rt = Roo.get(rt);
10901                 }
10902             }
10903             return rt;
10904         },
10905
10906         /**
10907          * Creates and wraps this element with another element
10908          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10909          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10910          * @return {HTMLElement/Element} The newly created wrapper element
10911          */
10912         wrap: function(config, returnDom){
10913             if(!config){
10914                 config = {tag: "div"};
10915             }
10916             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10917             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10918             return newEl;
10919         },
10920
10921         /**
10922          * Replaces the passed element with this element
10923          * @param {String/HTMLElement/Element} el The element to replace
10924          * @return {Roo.Element} this
10925          */
10926         replace: function(el){
10927             el = Roo.get(el);
10928             this.insertBefore(el);
10929             el.remove();
10930             return this;
10931         },
10932
10933         /**
10934          * Inserts an html fragment into this element
10935          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10936          * @param {String} html The HTML fragment
10937          * @param {Boolean} returnEl True to return an Roo.Element
10938          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10939          */
10940         insertHtml : function(where, html, returnEl){
10941             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10942             return returnEl ? Roo.get(el) : el;
10943         },
10944
10945         /**
10946          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10947          * @param {Object} o The object with the attributes
10948          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10949          * @return {Roo.Element} this
10950          */
10951         set : function(o, useSet){
10952             var el = this.dom;
10953             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10954             for(var attr in o){
10955                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10956                 if(attr=="cls"){
10957                     el.className = o["cls"];
10958                 }else{
10959                     if(useSet) {
10960                         el.setAttribute(attr, o[attr]);
10961                     } else {
10962                         el[attr] = o[attr];
10963                     }
10964                 }
10965             }
10966             if(o.style){
10967                 Roo.DomHelper.applyStyles(el, o.style);
10968             }
10969             return this;
10970         },
10971
10972         /**
10973          * Convenience method for constructing a KeyMap
10974          * @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:
10975          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10976          * @param {Function} fn The function to call
10977          * @param {Object} scope (optional) The scope of the function
10978          * @return {Roo.KeyMap} The KeyMap created
10979          */
10980         addKeyListener : function(key, fn, scope){
10981             var config;
10982             if(typeof key != "object" || key instanceof Array){
10983                 config = {
10984                     key: key,
10985                     fn: fn,
10986                     scope: scope
10987                 };
10988             }else{
10989                 config = {
10990                     key : key.key,
10991                     shift : key.shift,
10992                     ctrl : key.ctrl,
10993                     alt : key.alt,
10994                     fn: fn,
10995                     scope: scope
10996                 };
10997             }
10998             return new Roo.KeyMap(this, config);
10999         },
11000
11001         /**
11002          * Creates a KeyMap for this element
11003          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11004          * @return {Roo.KeyMap} The KeyMap created
11005          */
11006         addKeyMap : function(config){
11007             return new Roo.KeyMap(this, config);
11008         },
11009
11010         /**
11011          * Returns true if this element is scrollable.
11012          * @return {Boolean}
11013          */
11014          isScrollable : function(){
11015             var dom = this.dom;
11016             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11017         },
11018
11019         /**
11020          * 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().
11021          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11022          * @param {Number} value The new scroll value
11023          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11024          * @return {Element} this
11025          */
11026
11027         scrollTo : function(side, value, animate){
11028             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11029             if(!animate || !A){
11030                 this.dom[prop] = value;
11031             }else{
11032                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11033                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11034             }
11035             return this;
11036         },
11037
11038         /**
11039          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11040          * within this element's scrollable range.
11041          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11042          * @param {Number} distance How far to scroll the element in pixels
11043          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11044          * @return {Boolean} Returns true if a scroll was triggered or false if the element
11045          * was scrolled as far as it could go.
11046          */
11047          scroll : function(direction, distance, animate){
11048              if(!this.isScrollable()){
11049                  return;
11050              }
11051              var el = this.dom;
11052              var l = el.scrollLeft, t = el.scrollTop;
11053              var w = el.scrollWidth, h = el.scrollHeight;
11054              var cw = el.clientWidth, ch = el.clientHeight;
11055              direction = direction.toLowerCase();
11056              var scrolled = false;
11057              var a = this.preanim(arguments, 2);
11058              switch(direction){
11059                  case "l":
11060                  case "left":
11061                      if(w - l > cw){
11062                          var v = Math.min(l + distance, w-cw);
11063                          this.scrollTo("left", v, a);
11064                          scrolled = true;
11065                      }
11066                      break;
11067                 case "r":
11068                 case "right":
11069                      if(l > 0){
11070                          var v = Math.max(l - distance, 0);
11071                          this.scrollTo("left", v, a);
11072                          scrolled = true;
11073                      }
11074                      break;
11075                 case "t":
11076                 case "top":
11077                 case "up":
11078                      if(t > 0){
11079                          var v = Math.max(t - distance, 0);
11080                          this.scrollTo("top", v, a);
11081                          scrolled = true;
11082                      }
11083                      break;
11084                 case "b":
11085                 case "bottom":
11086                 case "down":
11087                      if(h - t > ch){
11088                          var v = Math.min(t + distance, h-ch);
11089                          this.scrollTo("top", v, a);
11090                          scrolled = true;
11091                      }
11092                      break;
11093              }
11094              return scrolled;
11095         },
11096
11097         /**
11098          * Translates the passed page coordinates into left/top css values for this element
11099          * @param {Number/Array} x The page x or an array containing [x, y]
11100          * @param {Number} y The page y
11101          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11102          */
11103         translatePoints : function(x, y){
11104             if(typeof x == 'object' || x instanceof Array){
11105                 y = x[1]; x = x[0];
11106             }
11107             var p = this.getStyle('position');
11108             var o = this.getXY();
11109
11110             var l = parseInt(this.getStyle('left'), 10);
11111             var t = parseInt(this.getStyle('top'), 10);
11112
11113             if(isNaN(l)){
11114                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11115             }
11116             if(isNaN(t)){
11117                 t = (p == "relative") ? 0 : this.dom.offsetTop;
11118             }
11119
11120             return {left: (x - o[0] + l), top: (y - o[1] + t)};
11121         },
11122
11123         /**
11124          * Returns the current scroll position of the element.
11125          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11126          */
11127         getScroll : function(){
11128             var d = this.dom, doc = document;
11129             if(d == doc || d == doc.body){
11130                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11131                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11132                 return {left: l, top: t};
11133             }else{
11134                 return {left: d.scrollLeft, top: d.scrollTop};
11135             }
11136         },
11137
11138         /**
11139          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11140          * are convert to standard 6 digit hex color.
11141          * @param {String} attr The css attribute
11142          * @param {String} defaultValue The default value to use when a valid color isn't found
11143          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11144          * YUI color anims.
11145          */
11146         getColor : function(attr, defaultValue, prefix){
11147             var v = this.getStyle(attr);
11148             if(!v || v == "transparent" || v == "inherit") {
11149                 return defaultValue;
11150             }
11151             var color = typeof prefix == "undefined" ? "#" : prefix;
11152             if(v.substr(0, 4) == "rgb("){
11153                 var rvs = v.slice(4, v.length -1).split(",");
11154                 for(var i = 0; i < 3; i++){
11155                     var h = parseInt(rvs[i]).toString(16);
11156                     if(h < 16){
11157                         h = "0" + h;
11158                     }
11159                     color += h;
11160                 }
11161             } else {
11162                 if(v.substr(0, 1) == "#"){
11163                     if(v.length == 4) {
11164                         for(var i = 1; i < 4; i++){
11165                             var c = v.charAt(i);
11166                             color +=  c + c;
11167                         }
11168                     }else if(v.length == 7){
11169                         color += v.substr(1);
11170                     }
11171                 }
11172             }
11173             return(color.length > 5 ? color.toLowerCase() : defaultValue);
11174         },
11175
11176         /**
11177          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11178          * gradient background, rounded corners and a 4-way shadow.
11179          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11180          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11181          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11182          * @return {Roo.Element} this
11183          */
11184         boxWrap : function(cls){
11185             cls = cls || 'x-box';
11186             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11187             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11188             return el;
11189         },
11190
11191         /**
11192          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11193          * @param {String} namespace The namespace in which to look for the attribute
11194          * @param {String} name The attribute name
11195          * @return {String} The attribute value
11196          */
11197         getAttributeNS : Roo.isIE ? function(ns, name){
11198             var d = this.dom;
11199             var type = typeof d[ns+":"+name];
11200             if(type != 'undefined' && type != 'unknown'){
11201                 return d[ns+":"+name];
11202             }
11203             return d[name];
11204         } : function(ns, name){
11205             var d = this.dom;
11206             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11207         },
11208         
11209         
11210         /**
11211          * Sets or Returns the value the dom attribute value
11212          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11213          * @param {String} value (optional) The value to set the attribute to
11214          * @return {String} The attribute value
11215          */
11216         attr : function(name){
11217             if (arguments.length > 1) {
11218                 this.dom.setAttribute(name, arguments[1]);
11219                 return arguments[1];
11220             }
11221             if (typeof(name) == 'object') {
11222                 for(var i in name) {
11223                     this.attr(i, name[i]);
11224                 }
11225                 return name;
11226             }
11227             
11228             
11229             if (!this.dom.hasAttribute(name)) {
11230                 return undefined;
11231             }
11232             return this.dom.getAttribute(name);
11233         }
11234         
11235         
11236         
11237     };
11238
11239     var ep = El.prototype;
11240
11241     /**
11242      * Appends an event handler (Shorthand for addListener)
11243      * @param {String}   eventName     The type of event to append
11244      * @param {Function} fn        The method the event invokes
11245      * @param {Object} scope       (optional) The scope (this object) of the fn
11246      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11247      * @method
11248      */
11249     ep.on = ep.addListener;
11250         // backwards compat
11251     ep.mon = ep.addListener;
11252
11253     /**
11254      * Removes an event handler from this element (shorthand for removeListener)
11255      * @param {String} eventName the type of event to remove
11256      * @param {Function} fn the method the event invokes
11257      * @return {Roo.Element} this
11258      * @method
11259      */
11260     ep.un = ep.removeListener;
11261
11262     /**
11263      * true to automatically adjust width and height settings for box-model issues (default to true)
11264      */
11265     ep.autoBoxAdjust = true;
11266
11267     // private
11268     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11269
11270     // private
11271     El.addUnits = function(v, defaultUnit){
11272         if(v === "" || v == "auto"){
11273             return v;
11274         }
11275         if(v === undefined){
11276             return '';
11277         }
11278         if(typeof v == "number" || !El.unitPattern.test(v)){
11279             return v + (defaultUnit || 'px');
11280         }
11281         return v;
11282     };
11283
11284     // special markup used throughout Roo when box wrapping elements
11285     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>';
11286     /**
11287      * Visibility mode constant - Use visibility to hide element
11288      * @static
11289      * @type Number
11290      */
11291     El.VISIBILITY = 1;
11292     /**
11293      * Visibility mode constant - Use display to hide element
11294      * @static
11295      * @type Number
11296      */
11297     El.DISPLAY = 2;
11298
11299     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11300     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11301     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11302
11303
11304
11305     /**
11306      * @private
11307      */
11308     El.cache = {};
11309
11310     var docEl;
11311
11312     /**
11313      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11314      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11315      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11316      * @return {Element} The Element object
11317      * @static
11318      */
11319     El.get = function(el){
11320         var ex, elm, id;
11321         if(!el){ return null; }
11322         if(typeof el == "string"){ // element id
11323             if(!(elm = document.getElementById(el))){
11324                 return null;
11325             }
11326             if(ex = El.cache[el]){
11327                 ex.dom = elm;
11328             }else{
11329                 ex = El.cache[el] = new El(elm);
11330             }
11331             return ex;
11332         }else if(el.tagName){ // dom element
11333             if(!(id = el.id)){
11334                 id = Roo.id(el);
11335             }
11336             if(ex = El.cache[id]){
11337                 ex.dom = el;
11338             }else{
11339                 ex = El.cache[id] = new El(el);
11340             }
11341             return ex;
11342         }else if(el instanceof El){
11343             if(el != docEl){
11344                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11345                                                               // catch case where it hasn't been appended
11346                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11347             }
11348             return el;
11349         }else if(el.isComposite){
11350             return el;
11351         }else if(el instanceof Array){
11352             return El.select(el);
11353         }else if(el == document){
11354             // create a bogus element object representing the document object
11355             if(!docEl){
11356                 var f = function(){};
11357                 f.prototype = El.prototype;
11358                 docEl = new f();
11359                 docEl.dom = document;
11360             }
11361             return docEl;
11362         }
11363         return null;
11364     };
11365
11366     // private
11367     El.uncache = function(el){
11368         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11369             if(a[i]){
11370                 delete El.cache[a[i].id || a[i]];
11371             }
11372         }
11373     };
11374
11375     // private
11376     // Garbage collection - uncache elements/purge listeners on orphaned elements
11377     // so we don't hold a reference and cause the browser to retain them
11378     El.garbageCollect = function(){
11379         if(!Roo.enableGarbageCollector){
11380             clearInterval(El.collectorThread);
11381             return;
11382         }
11383         for(var eid in El.cache){
11384             var el = El.cache[eid], d = el.dom;
11385             // -------------------------------------------------------
11386             // Determining what is garbage:
11387             // -------------------------------------------------------
11388             // !d
11389             // dom node is null, definitely garbage
11390             // -------------------------------------------------------
11391             // !d.parentNode
11392             // no parentNode == direct orphan, definitely garbage
11393             // -------------------------------------------------------
11394             // !d.offsetParent && !document.getElementById(eid)
11395             // display none elements have no offsetParent so we will
11396             // also try to look it up by it's id. However, check
11397             // offsetParent first so we don't do unneeded lookups.
11398             // This enables collection of elements that are not orphans
11399             // directly, but somewhere up the line they have an orphan
11400             // parent.
11401             // -------------------------------------------------------
11402             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11403                 delete El.cache[eid];
11404                 if(d && Roo.enableListenerCollection){
11405                     E.purgeElement(d);
11406                 }
11407             }
11408         }
11409     }
11410     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11411
11412
11413     // dom is optional
11414     El.Flyweight = function(dom){
11415         this.dom = dom;
11416     };
11417     El.Flyweight.prototype = El.prototype;
11418
11419     El._flyweights = {};
11420     /**
11421      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11422      * the dom node can be overwritten by other code.
11423      * @param {String/HTMLElement} el The dom node or id
11424      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11425      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11426      * @static
11427      * @return {Element} The shared Element object
11428      */
11429     El.fly = function(el, named){
11430         named = named || '_global';
11431         el = Roo.getDom(el);
11432         if(!el){
11433             return null;
11434         }
11435         if(!El._flyweights[named]){
11436             El._flyweights[named] = new El.Flyweight();
11437         }
11438         El._flyweights[named].dom = el;
11439         return El._flyweights[named];
11440     };
11441
11442     /**
11443      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11444      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11445      * Shorthand of {@link Roo.Element#get}
11446      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11447      * @return {Element} The Element object
11448      * @member Roo
11449      * @method get
11450      */
11451     Roo.get = El.get;
11452     /**
11453      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11454      * the dom node can be overwritten by other code.
11455      * Shorthand of {@link Roo.Element#fly}
11456      * @param {String/HTMLElement} el The dom node or id
11457      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11458      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11459      * @static
11460      * @return {Element} The shared Element object
11461      * @member Roo
11462      * @method fly
11463      */
11464     Roo.fly = El.fly;
11465
11466     // speedy lookup for elements never to box adjust
11467     var noBoxAdjust = Roo.isStrict ? {
11468         select:1
11469     } : {
11470         input:1, select:1, textarea:1
11471     };
11472     if(Roo.isIE || Roo.isGecko){
11473         noBoxAdjust['button'] = 1;
11474     }
11475
11476
11477     Roo.EventManager.on(window, 'unload', function(){
11478         delete El.cache;
11479         delete El._flyweights;
11480     });
11481 })();
11482
11483
11484
11485
11486 if(Roo.DomQuery){
11487     Roo.Element.selectorFunction = Roo.DomQuery.select;
11488 }
11489
11490 Roo.Element.select = function(selector, unique, root){
11491     var els;
11492     if(typeof selector == "string"){
11493         els = Roo.Element.selectorFunction(selector, root);
11494     }else if(selector.length !== undefined){
11495         els = selector;
11496     }else{
11497         throw "Invalid selector";
11498     }
11499     if(unique === true){
11500         return new Roo.CompositeElement(els);
11501     }else{
11502         return new Roo.CompositeElementLite(els);
11503     }
11504 };
11505 /**
11506  * Selects elements based on the passed CSS selector to enable working on them as 1.
11507  * @param {String/Array} selector The CSS selector or an array of elements
11508  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11509  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11510  * @return {CompositeElementLite/CompositeElement}
11511  * @member Roo
11512  * @method select
11513  */
11514 Roo.select = Roo.Element.select;
11515
11516
11517
11518
11519
11520
11521
11522
11523
11524
11525
11526
11527
11528
11529 /*
11530  * Based on:
11531  * Ext JS Library 1.1.1
11532  * Copyright(c) 2006-2007, Ext JS, LLC.
11533  *
11534  * Originally Released Under LGPL - original licence link has changed is not relivant.
11535  *
11536  * Fork - LGPL
11537  * <script type="text/javascript">
11538  */
11539
11540
11541
11542 //Notifies Element that fx methods are available
11543 Roo.enableFx = true;
11544
11545 /**
11546  * @class Roo.Fx
11547  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11548  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11549  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11550  * Element effects to work.</p><br/>
11551  *
11552  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11553  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11554  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11555  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11556  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11557  * expected results and should be done with care.</p><br/>
11558  *
11559  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11560  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11561 <pre>
11562 Value  Description
11563 -----  -----------------------------
11564 tl     The top left corner
11565 t      The center of the top edge
11566 tr     The top right corner
11567 l      The center of the left edge
11568 r      The center of the right edge
11569 bl     The bottom left corner
11570 b      The center of the bottom edge
11571 br     The bottom right corner
11572 </pre>
11573  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11574  * below are common options that can be passed to any Fx method.</b>
11575  * @cfg {Function} callback A function called when the effect is finished
11576  * @cfg {Object} scope The scope of the effect function
11577  * @cfg {String} easing A valid Easing value for the effect
11578  * @cfg {String} afterCls A css class to apply after the effect
11579  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11580  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11581  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11582  * effects that end with the element being visually hidden, ignored otherwise)
11583  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11584  * a function which returns such a specification that will be applied to the Element after the effect finishes
11585  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11586  * @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
11587  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11588  */
11589 Roo.Fx = {
11590         /**
11591          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11592          * origin for the slide effect.  This function automatically handles wrapping the element with
11593          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11594          * Usage:
11595          *<pre><code>
11596 // default: slide the element in from the top
11597 el.slideIn();
11598
11599 // custom: slide the element in from the right with a 2-second duration
11600 el.slideIn('r', { duration: 2 });
11601
11602 // common config options shown with default values
11603 el.slideIn('t', {
11604     easing: 'easeOut',
11605     duration: .5
11606 });
11607 </code></pre>
11608          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11609          * @param {Object} options (optional) Object literal with any of the Fx config options
11610          * @return {Roo.Element} The Element
11611          */
11612     slideIn : function(anchor, o){
11613         var el = this.getFxEl();
11614         o = o || {};
11615
11616         el.queueFx(o, function(){
11617
11618             anchor = anchor || "t";
11619
11620             // fix display to visibility
11621             this.fixDisplay();
11622
11623             // restore values after effect
11624             var r = this.getFxRestore();
11625             var b = this.getBox();
11626             // fixed size for slide
11627             this.setSize(b);
11628
11629             // wrap if needed
11630             var wrap = this.fxWrap(r.pos, o, "hidden");
11631
11632             var st = this.dom.style;
11633             st.visibility = "visible";
11634             st.position = "absolute";
11635
11636             // clear out temp styles after slide and unwrap
11637             var after = function(){
11638                 el.fxUnwrap(wrap, r.pos, o);
11639                 st.width = r.width;
11640                 st.height = r.height;
11641                 el.afterFx(o);
11642             };
11643             // time to calc the positions
11644             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11645
11646             switch(anchor.toLowerCase()){
11647                 case "t":
11648                     wrap.setSize(b.width, 0);
11649                     st.left = st.bottom = "0";
11650                     a = {height: bh};
11651                 break;
11652                 case "l":
11653                     wrap.setSize(0, b.height);
11654                     st.right = st.top = "0";
11655                     a = {width: bw};
11656                 break;
11657                 case "r":
11658                     wrap.setSize(0, b.height);
11659                     wrap.setX(b.right);
11660                     st.left = st.top = "0";
11661                     a = {width: bw, points: pt};
11662                 break;
11663                 case "b":
11664                     wrap.setSize(b.width, 0);
11665                     wrap.setY(b.bottom);
11666                     st.left = st.top = "0";
11667                     a = {height: bh, points: pt};
11668                 break;
11669                 case "tl":
11670                     wrap.setSize(0, 0);
11671                     st.right = st.bottom = "0";
11672                     a = {width: bw, height: bh};
11673                 break;
11674                 case "bl":
11675                     wrap.setSize(0, 0);
11676                     wrap.setY(b.y+b.height);
11677                     st.right = st.top = "0";
11678                     a = {width: bw, height: bh, points: pt};
11679                 break;
11680                 case "br":
11681                     wrap.setSize(0, 0);
11682                     wrap.setXY([b.right, b.bottom]);
11683                     st.left = st.top = "0";
11684                     a = {width: bw, height: bh, points: pt};
11685                 break;
11686                 case "tr":
11687                     wrap.setSize(0, 0);
11688                     wrap.setX(b.x+b.width);
11689                     st.left = st.bottom = "0";
11690                     a = {width: bw, height: bh, points: pt};
11691                 break;
11692             }
11693             this.dom.style.visibility = "visible";
11694             wrap.show();
11695
11696             arguments.callee.anim = wrap.fxanim(a,
11697                 o,
11698                 'motion',
11699                 .5,
11700                 'easeOut', after);
11701         });
11702         return this;
11703     },
11704     
11705         /**
11706          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11707          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11708          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11709          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11710          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11711          * Usage:
11712          *<pre><code>
11713 // default: slide the element out to the top
11714 el.slideOut();
11715
11716 // custom: slide the element out to the right with a 2-second duration
11717 el.slideOut('r', { duration: 2 });
11718
11719 // common config options shown with default values
11720 el.slideOut('t', {
11721     easing: 'easeOut',
11722     duration: .5,
11723     remove: false,
11724     useDisplay: false
11725 });
11726 </code></pre>
11727          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11728          * @param {Object} options (optional) Object literal with any of the Fx config options
11729          * @return {Roo.Element} The Element
11730          */
11731     slideOut : function(anchor, o){
11732         var el = this.getFxEl();
11733         o = o || {};
11734
11735         el.queueFx(o, function(){
11736
11737             anchor = anchor || "t";
11738
11739             // restore values after effect
11740             var r = this.getFxRestore();
11741             
11742             var b = this.getBox();
11743             // fixed size for slide
11744             this.setSize(b);
11745
11746             // wrap if needed
11747             var wrap = this.fxWrap(r.pos, o, "visible");
11748
11749             var st = this.dom.style;
11750             st.visibility = "visible";
11751             st.position = "absolute";
11752
11753             wrap.setSize(b);
11754
11755             var after = function(){
11756                 if(o.useDisplay){
11757                     el.setDisplayed(false);
11758                 }else{
11759                     el.hide();
11760                 }
11761
11762                 el.fxUnwrap(wrap, r.pos, o);
11763
11764                 st.width = r.width;
11765                 st.height = r.height;
11766
11767                 el.afterFx(o);
11768             };
11769
11770             var a, zero = {to: 0};
11771             switch(anchor.toLowerCase()){
11772                 case "t":
11773                     st.left = st.bottom = "0";
11774                     a = {height: zero};
11775                 break;
11776                 case "l":
11777                     st.right = st.top = "0";
11778                     a = {width: zero};
11779                 break;
11780                 case "r":
11781                     st.left = st.top = "0";
11782                     a = {width: zero, points: {to:[b.right, b.y]}};
11783                 break;
11784                 case "b":
11785                     st.left = st.top = "0";
11786                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11787                 break;
11788                 case "tl":
11789                     st.right = st.bottom = "0";
11790                     a = {width: zero, height: zero};
11791                 break;
11792                 case "bl":
11793                     st.right = st.top = "0";
11794                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11795                 break;
11796                 case "br":
11797                     st.left = st.top = "0";
11798                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11799                 break;
11800                 case "tr":
11801                     st.left = st.bottom = "0";
11802                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11803                 break;
11804             }
11805
11806             arguments.callee.anim = wrap.fxanim(a,
11807                 o,
11808                 'motion',
11809                 .5,
11810                 "easeOut", after);
11811         });
11812         return this;
11813     },
11814
11815         /**
11816          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11817          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11818          * The element must be removed from the DOM using the 'remove' config option if desired.
11819          * Usage:
11820          *<pre><code>
11821 // default
11822 el.puff();
11823
11824 // common config options shown with default values
11825 el.puff({
11826     easing: 'easeOut',
11827     duration: .5,
11828     remove: false,
11829     useDisplay: false
11830 });
11831 </code></pre>
11832          * @param {Object} options (optional) Object literal with any of the Fx config options
11833          * @return {Roo.Element} The Element
11834          */
11835     puff : function(o){
11836         var el = this.getFxEl();
11837         o = o || {};
11838
11839         el.queueFx(o, function(){
11840             this.clearOpacity();
11841             this.show();
11842
11843             // restore values after effect
11844             var r = this.getFxRestore();
11845             var st = this.dom.style;
11846
11847             var after = function(){
11848                 if(o.useDisplay){
11849                     el.setDisplayed(false);
11850                 }else{
11851                     el.hide();
11852                 }
11853
11854                 el.clearOpacity();
11855
11856                 el.setPositioning(r.pos);
11857                 st.width = r.width;
11858                 st.height = r.height;
11859                 st.fontSize = '';
11860                 el.afterFx(o);
11861             };
11862
11863             var width = this.getWidth();
11864             var height = this.getHeight();
11865
11866             arguments.callee.anim = this.fxanim({
11867                     width : {to: this.adjustWidth(width * 2)},
11868                     height : {to: this.adjustHeight(height * 2)},
11869                     points : {by: [-(width * .5), -(height * .5)]},
11870                     opacity : {to: 0},
11871                     fontSize: {to:200, unit: "%"}
11872                 },
11873                 o,
11874                 'motion',
11875                 .5,
11876                 "easeOut", after);
11877         });
11878         return this;
11879     },
11880
11881         /**
11882          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11883          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11884          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11885          * Usage:
11886          *<pre><code>
11887 // default
11888 el.switchOff();
11889
11890 // all config options shown with default values
11891 el.switchOff({
11892     easing: 'easeIn',
11893     duration: .3,
11894     remove: false,
11895     useDisplay: false
11896 });
11897 </code></pre>
11898          * @param {Object} options (optional) Object literal with any of the Fx config options
11899          * @return {Roo.Element} The Element
11900          */
11901     switchOff : function(o){
11902         var el = this.getFxEl();
11903         o = o || {};
11904
11905         el.queueFx(o, function(){
11906             this.clearOpacity();
11907             this.clip();
11908
11909             // restore values after effect
11910             var r = this.getFxRestore();
11911             var st = this.dom.style;
11912
11913             var after = function(){
11914                 if(o.useDisplay){
11915                     el.setDisplayed(false);
11916                 }else{
11917                     el.hide();
11918                 }
11919
11920                 el.clearOpacity();
11921                 el.setPositioning(r.pos);
11922                 st.width = r.width;
11923                 st.height = r.height;
11924
11925                 el.afterFx(o);
11926             };
11927
11928             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11929                 this.clearOpacity();
11930                 (function(){
11931                     this.fxanim({
11932                         height:{to:1},
11933                         points:{by:[0, this.getHeight() * .5]}
11934                     }, o, 'motion', 0.3, 'easeIn', after);
11935                 }).defer(100, this);
11936             });
11937         });
11938         return this;
11939     },
11940
11941     /**
11942      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11943      * changed using the "attr" config option) and then fading back to the original color. If no original
11944      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11945      * Usage:
11946 <pre><code>
11947 // default: highlight background to yellow
11948 el.highlight();
11949
11950 // custom: highlight foreground text to blue for 2 seconds
11951 el.highlight("0000ff", { attr: 'color', duration: 2 });
11952
11953 // common config options shown with default values
11954 el.highlight("ffff9c", {
11955     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11956     endColor: (current color) or "ffffff",
11957     easing: 'easeIn',
11958     duration: 1
11959 });
11960 </code></pre>
11961      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11962      * @param {Object} options (optional) Object literal with any of the Fx config options
11963      * @return {Roo.Element} The Element
11964      */ 
11965     highlight : function(color, o){
11966         var el = this.getFxEl();
11967         o = o || {};
11968
11969         el.queueFx(o, function(){
11970             color = color || "ffff9c";
11971             attr = o.attr || "backgroundColor";
11972
11973             this.clearOpacity();
11974             this.show();
11975
11976             var origColor = this.getColor(attr);
11977             var restoreColor = this.dom.style[attr];
11978             endColor = (o.endColor || origColor) || "ffffff";
11979
11980             var after = function(){
11981                 el.dom.style[attr] = restoreColor;
11982                 el.afterFx(o);
11983             };
11984
11985             var a = {};
11986             a[attr] = {from: color, to: endColor};
11987             arguments.callee.anim = this.fxanim(a,
11988                 o,
11989                 'color',
11990                 1,
11991                 'easeIn', after);
11992         });
11993         return this;
11994     },
11995
11996    /**
11997     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11998     * Usage:
11999 <pre><code>
12000 // default: a single light blue ripple
12001 el.frame();
12002
12003 // custom: 3 red ripples lasting 3 seconds total
12004 el.frame("ff0000", 3, { duration: 3 });
12005
12006 // common config options shown with default values
12007 el.frame("C3DAF9", 1, {
12008     duration: 1 //duration of entire animation (not each individual ripple)
12009     // Note: Easing is not configurable and will be ignored if included
12010 });
12011 </code></pre>
12012     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12013     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12014     * @param {Object} options (optional) Object literal with any of the Fx config options
12015     * @return {Roo.Element} The Element
12016     */
12017     frame : function(color, count, o){
12018         var el = this.getFxEl();
12019         o = o || {};
12020
12021         el.queueFx(o, function(){
12022             color = color || "#C3DAF9";
12023             if(color.length == 6){
12024                 color = "#" + color;
12025             }
12026             count = count || 1;
12027             duration = o.duration || 1;
12028             this.show();
12029
12030             var b = this.getBox();
12031             var animFn = function(){
12032                 var proxy = this.createProxy({
12033
12034                      style:{
12035                         visbility:"hidden",
12036                         position:"absolute",
12037                         "z-index":"35000", // yee haw
12038                         border:"0px solid " + color
12039                      }
12040                   });
12041                 var scale = Roo.isBorderBox ? 2 : 1;
12042                 proxy.animate({
12043                     top:{from:b.y, to:b.y - 20},
12044                     left:{from:b.x, to:b.x - 20},
12045                     borderWidth:{from:0, to:10},
12046                     opacity:{from:1, to:0},
12047                     height:{from:b.height, to:(b.height + (20*scale))},
12048                     width:{from:b.width, to:(b.width + (20*scale))}
12049                 }, duration, function(){
12050                     proxy.remove();
12051                 });
12052                 if(--count > 0){
12053                      animFn.defer((duration/2)*1000, this);
12054                 }else{
12055                     el.afterFx(o);
12056                 }
12057             };
12058             animFn.call(this);
12059         });
12060         return this;
12061     },
12062
12063    /**
12064     * Creates a pause before any subsequent queued effects begin.  If there are
12065     * no effects queued after the pause it will have no effect.
12066     * Usage:
12067 <pre><code>
12068 el.pause(1);
12069 </code></pre>
12070     * @param {Number} seconds The length of time to pause (in seconds)
12071     * @return {Roo.Element} The Element
12072     */
12073     pause : function(seconds){
12074         var el = this.getFxEl();
12075         var o = {};
12076
12077         el.queueFx(o, function(){
12078             setTimeout(function(){
12079                 el.afterFx(o);
12080             }, seconds * 1000);
12081         });
12082         return this;
12083     },
12084
12085    /**
12086     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
12087     * using the "endOpacity" config option.
12088     * Usage:
12089 <pre><code>
12090 // default: fade in from opacity 0 to 100%
12091 el.fadeIn();
12092
12093 // custom: fade in from opacity 0 to 75% over 2 seconds
12094 el.fadeIn({ endOpacity: .75, duration: 2});
12095
12096 // common config options shown with default values
12097 el.fadeIn({
12098     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12099     easing: 'easeOut',
12100     duration: .5
12101 });
12102 </code></pre>
12103     * @param {Object} options (optional) Object literal with any of the Fx config options
12104     * @return {Roo.Element} The Element
12105     */
12106     fadeIn : function(o){
12107         var el = this.getFxEl();
12108         o = o || {};
12109         el.queueFx(o, function(){
12110             this.setOpacity(0);
12111             this.fixDisplay();
12112             this.dom.style.visibility = 'visible';
12113             var to = o.endOpacity || 1;
12114             arguments.callee.anim = this.fxanim({opacity:{to:to}},
12115                 o, null, .5, "easeOut", function(){
12116                 if(to == 1){
12117                     this.clearOpacity();
12118                 }
12119                 el.afterFx(o);
12120             });
12121         });
12122         return this;
12123     },
12124
12125    /**
12126     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
12127     * using the "endOpacity" config option.
12128     * Usage:
12129 <pre><code>
12130 // default: fade out from the element's current opacity to 0
12131 el.fadeOut();
12132
12133 // custom: fade out from the element's current opacity to 25% over 2 seconds
12134 el.fadeOut({ endOpacity: .25, duration: 2});
12135
12136 // common config options shown with default values
12137 el.fadeOut({
12138     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12139     easing: 'easeOut',
12140     duration: .5
12141     remove: false,
12142     useDisplay: false
12143 });
12144 </code></pre>
12145     * @param {Object} options (optional) Object literal with any of the Fx config options
12146     * @return {Roo.Element} The Element
12147     */
12148     fadeOut : function(o){
12149         var el = this.getFxEl();
12150         o = o || {};
12151         el.queueFx(o, function(){
12152             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12153                 o, null, .5, "easeOut", function(){
12154                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12155                      this.dom.style.display = "none";
12156                 }else{
12157                      this.dom.style.visibility = "hidden";
12158                 }
12159                 this.clearOpacity();
12160                 el.afterFx(o);
12161             });
12162         });
12163         return this;
12164     },
12165
12166    /**
12167     * Animates the transition of an element's dimensions from a starting height/width
12168     * to an ending height/width.
12169     * Usage:
12170 <pre><code>
12171 // change height and width to 100x100 pixels
12172 el.scale(100, 100);
12173
12174 // common config options shown with default values.  The height and width will default to
12175 // the element's existing values if passed as null.
12176 el.scale(
12177     [element's width],
12178     [element's height], {
12179     easing: 'easeOut',
12180     duration: .35
12181 });
12182 </code></pre>
12183     * @param {Number} width  The new width (pass undefined to keep the original width)
12184     * @param {Number} height  The new height (pass undefined to keep the original height)
12185     * @param {Object} options (optional) Object literal with any of the Fx config options
12186     * @return {Roo.Element} The Element
12187     */
12188     scale : function(w, h, o){
12189         this.shift(Roo.apply({}, o, {
12190             width: w,
12191             height: h
12192         }));
12193         return this;
12194     },
12195
12196    /**
12197     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12198     * Any of these properties not specified in the config object will not be changed.  This effect 
12199     * requires that at least one new dimension, position or opacity setting must be passed in on
12200     * the config object in order for the function to have any effect.
12201     * Usage:
12202 <pre><code>
12203 // slide the element horizontally to x position 200 while changing the height and opacity
12204 el.shift({ x: 200, height: 50, opacity: .8 });
12205
12206 // common config options shown with default values.
12207 el.shift({
12208     width: [element's width],
12209     height: [element's height],
12210     x: [element's x position],
12211     y: [element's y position],
12212     opacity: [element's opacity],
12213     easing: 'easeOut',
12214     duration: .35
12215 });
12216 </code></pre>
12217     * @param {Object} options  Object literal with any of the Fx config options
12218     * @return {Roo.Element} The Element
12219     */
12220     shift : function(o){
12221         var el = this.getFxEl();
12222         o = o || {};
12223         el.queueFx(o, function(){
12224             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12225             if(w !== undefined){
12226                 a.width = {to: this.adjustWidth(w)};
12227             }
12228             if(h !== undefined){
12229                 a.height = {to: this.adjustHeight(h)};
12230             }
12231             if(x !== undefined || y !== undefined){
12232                 a.points = {to: [
12233                     x !== undefined ? x : this.getX(),
12234                     y !== undefined ? y : this.getY()
12235                 ]};
12236             }
12237             if(op !== undefined){
12238                 a.opacity = {to: op};
12239             }
12240             if(o.xy !== undefined){
12241                 a.points = {to: o.xy};
12242             }
12243             arguments.callee.anim = this.fxanim(a,
12244                 o, 'motion', .35, "easeOut", function(){
12245                 el.afterFx(o);
12246             });
12247         });
12248         return this;
12249     },
12250
12251         /**
12252          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12253          * ending point of the effect.
12254          * Usage:
12255          *<pre><code>
12256 // default: slide the element downward while fading out
12257 el.ghost();
12258
12259 // custom: slide the element out to the right with a 2-second duration
12260 el.ghost('r', { duration: 2 });
12261
12262 // common config options shown with default values
12263 el.ghost('b', {
12264     easing: 'easeOut',
12265     duration: .5
12266     remove: false,
12267     useDisplay: false
12268 });
12269 </code></pre>
12270          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12271          * @param {Object} options (optional) Object literal with any of the Fx config options
12272          * @return {Roo.Element} The Element
12273          */
12274     ghost : function(anchor, o){
12275         var el = this.getFxEl();
12276         o = o || {};
12277
12278         el.queueFx(o, function(){
12279             anchor = anchor || "b";
12280
12281             // restore values after effect
12282             var r = this.getFxRestore();
12283             var w = this.getWidth(),
12284                 h = this.getHeight();
12285
12286             var st = this.dom.style;
12287
12288             var after = function(){
12289                 if(o.useDisplay){
12290                     el.setDisplayed(false);
12291                 }else{
12292                     el.hide();
12293                 }
12294
12295                 el.clearOpacity();
12296                 el.setPositioning(r.pos);
12297                 st.width = r.width;
12298                 st.height = r.height;
12299
12300                 el.afterFx(o);
12301             };
12302
12303             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12304             switch(anchor.toLowerCase()){
12305                 case "t":
12306                     pt.by = [0, -h];
12307                 break;
12308                 case "l":
12309                     pt.by = [-w, 0];
12310                 break;
12311                 case "r":
12312                     pt.by = [w, 0];
12313                 break;
12314                 case "b":
12315                     pt.by = [0, h];
12316                 break;
12317                 case "tl":
12318                     pt.by = [-w, -h];
12319                 break;
12320                 case "bl":
12321                     pt.by = [-w, h];
12322                 break;
12323                 case "br":
12324                     pt.by = [w, h];
12325                 break;
12326                 case "tr":
12327                     pt.by = [w, -h];
12328                 break;
12329             }
12330
12331             arguments.callee.anim = this.fxanim(a,
12332                 o,
12333                 'motion',
12334                 .5,
12335                 "easeOut", after);
12336         });
12337         return this;
12338     },
12339
12340         /**
12341          * Ensures that all effects queued after syncFx is called on the element are
12342          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12343          * @return {Roo.Element} The Element
12344          */
12345     syncFx : function(){
12346         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12347             block : false,
12348             concurrent : true,
12349             stopFx : false
12350         });
12351         return this;
12352     },
12353
12354         /**
12355          * Ensures that all effects queued after sequenceFx is called on the element are
12356          * run in sequence.  This is the opposite of {@link #syncFx}.
12357          * @return {Roo.Element} The Element
12358          */
12359     sequenceFx : function(){
12360         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12361             block : false,
12362             concurrent : false,
12363             stopFx : false
12364         });
12365         return this;
12366     },
12367
12368         /* @private */
12369     nextFx : function(){
12370         var ef = this.fxQueue[0];
12371         if(ef){
12372             ef.call(this);
12373         }
12374     },
12375
12376         /**
12377          * Returns true if the element has any effects actively running or queued, else returns false.
12378          * @return {Boolean} True if element has active effects, else false
12379          */
12380     hasActiveFx : function(){
12381         return this.fxQueue && this.fxQueue[0];
12382     },
12383
12384         /**
12385          * Stops any running effects and clears the element's internal effects queue if it contains
12386          * any additional effects that haven't started yet.
12387          * @return {Roo.Element} The Element
12388          */
12389     stopFx : function(){
12390         if(this.hasActiveFx()){
12391             var cur = this.fxQueue[0];
12392             if(cur && cur.anim && cur.anim.isAnimated()){
12393                 this.fxQueue = [cur]; // clear out others
12394                 cur.anim.stop(true);
12395             }
12396         }
12397         return this;
12398     },
12399
12400         /* @private */
12401     beforeFx : function(o){
12402         if(this.hasActiveFx() && !o.concurrent){
12403            if(o.stopFx){
12404                this.stopFx();
12405                return true;
12406            }
12407            return false;
12408         }
12409         return true;
12410     },
12411
12412         /**
12413          * Returns true if the element is currently blocking so that no other effect can be queued
12414          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12415          * used to ensure that an effect initiated by a user action runs to completion prior to the
12416          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12417          * @return {Boolean} True if blocking, else false
12418          */
12419     hasFxBlock : function(){
12420         var q = this.fxQueue;
12421         return q && q[0] && q[0].block;
12422     },
12423
12424         /* @private */
12425     queueFx : function(o, fn){
12426         if(!this.fxQueue){
12427             this.fxQueue = [];
12428         }
12429         if(!this.hasFxBlock()){
12430             Roo.applyIf(o, this.fxDefaults);
12431             if(!o.concurrent){
12432                 var run = this.beforeFx(o);
12433                 fn.block = o.block;
12434                 this.fxQueue.push(fn);
12435                 if(run){
12436                     this.nextFx();
12437                 }
12438             }else{
12439                 fn.call(this);
12440             }
12441         }
12442         return this;
12443     },
12444
12445         /* @private */
12446     fxWrap : function(pos, o, vis){
12447         var wrap;
12448         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12449             var wrapXY;
12450             if(o.fixPosition){
12451                 wrapXY = this.getXY();
12452             }
12453             var div = document.createElement("div");
12454             div.style.visibility = vis;
12455             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12456             wrap.setPositioning(pos);
12457             if(wrap.getStyle("position") == "static"){
12458                 wrap.position("relative");
12459             }
12460             this.clearPositioning('auto');
12461             wrap.clip();
12462             wrap.dom.appendChild(this.dom);
12463             if(wrapXY){
12464                 wrap.setXY(wrapXY);
12465             }
12466         }
12467         return wrap;
12468     },
12469
12470         /* @private */
12471     fxUnwrap : function(wrap, pos, o){
12472         this.clearPositioning();
12473         this.setPositioning(pos);
12474         if(!o.wrap){
12475             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12476             wrap.remove();
12477         }
12478     },
12479
12480         /* @private */
12481     getFxRestore : function(){
12482         var st = this.dom.style;
12483         return {pos: this.getPositioning(), width: st.width, height : st.height};
12484     },
12485
12486         /* @private */
12487     afterFx : function(o){
12488         if(o.afterStyle){
12489             this.applyStyles(o.afterStyle);
12490         }
12491         if(o.afterCls){
12492             this.addClass(o.afterCls);
12493         }
12494         if(o.remove === true){
12495             this.remove();
12496         }
12497         Roo.callback(o.callback, o.scope, [this]);
12498         if(!o.concurrent){
12499             this.fxQueue.shift();
12500             this.nextFx();
12501         }
12502     },
12503
12504         /* @private */
12505     getFxEl : function(){ // support for composite element fx
12506         return Roo.get(this.dom);
12507     },
12508
12509         /* @private */
12510     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12511         animType = animType || 'run';
12512         opt = opt || {};
12513         var anim = Roo.lib.Anim[animType](
12514             this.dom, args,
12515             (opt.duration || defaultDur) || .35,
12516             (opt.easing || defaultEase) || 'easeOut',
12517             function(){
12518                 Roo.callback(cb, this);
12519             },
12520             this
12521         );
12522         opt.anim = anim;
12523         return anim;
12524     }
12525 };
12526
12527 // backwords compat
12528 Roo.Fx.resize = Roo.Fx.scale;
12529
12530 //When included, Roo.Fx is automatically applied to Element so that all basic
12531 //effects are available directly via the Element API
12532 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12533  * Based on:
12534  * Ext JS Library 1.1.1
12535  * Copyright(c) 2006-2007, Ext JS, LLC.
12536  *
12537  * Originally Released Under LGPL - original licence link has changed is not relivant.
12538  *
12539  * Fork - LGPL
12540  * <script type="text/javascript">
12541  */
12542
12543
12544 /**
12545  * @class Roo.CompositeElement
12546  * Standard composite class. Creates a Roo.Element for every element in the collection.
12547  * <br><br>
12548  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12549  * actions will be performed on all the elements in this collection.</b>
12550  * <br><br>
12551  * All methods return <i>this</i> and can be chained.
12552  <pre><code>
12553  var els = Roo.select("#some-el div.some-class", true);
12554  // or select directly from an existing element
12555  var el = Roo.get('some-el');
12556  el.select('div.some-class', true);
12557
12558  els.setWidth(100); // all elements become 100 width
12559  els.hide(true); // all elements fade out and hide
12560  // or
12561  els.setWidth(100).hide(true);
12562  </code></pre>
12563  */
12564 Roo.CompositeElement = function(els){
12565     this.elements = [];
12566     this.addElements(els);
12567 };
12568 Roo.CompositeElement.prototype = {
12569     isComposite: true,
12570     addElements : function(els){
12571         if(!els) {
12572             return this;
12573         }
12574         if(typeof els == "string"){
12575             els = Roo.Element.selectorFunction(els);
12576         }
12577         var yels = this.elements;
12578         var index = yels.length-1;
12579         for(var i = 0, len = els.length; i < len; i++) {
12580                 yels[++index] = Roo.get(els[i]);
12581         }
12582         return this;
12583     },
12584
12585     /**
12586     * Clears this composite and adds the elements returned by the passed selector.
12587     * @param {String/Array} els A string CSS selector, an array of elements or an element
12588     * @return {CompositeElement} this
12589     */
12590     fill : function(els){
12591         this.elements = [];
12592         this.add(els);
12593         return this;
12594     },
12595
12596     /**
12597     * Filters this composite to only elements that match the passed selector.
12598     * @param {String} selector A string CSS selector
12599     * @param {Boolean} inverse return inverse filter (not matches)
12600     * @return {CompositeElement} this
12601     */
12602     filter : function(selector, inverse){
12603         var els = [];
12604         inverse = inverse || false;
12605         this.each(function(el){
12606             var match = inverse ? !el.is(selector) : el.is(selector);
12607             if(match){
12608                 els[els.length] = el.dom;
12609             }
12610         });
12611         this.fill(els);
12612         return this;
12613     },
12614
12615     invoke : function(fn, args){
12616         var els = this.elements;
12617         for(var i = 0, len = els.length; i < len; i++) {
12618                 Roo.Element.prototype[fn].apply(els[i], args);
12619         }
12620         return this;
12621     },
12622     /**
12623     * Adds elements to this composite.
12624     * @param {String/Array} els A string CSS selector, an array of elements or an element
12625     * @return {CompositeElement} this
12626     */
12627     add : function(els){
12628         if(typeof els == "string"){
12629             this.addElements(Roo.Element.selectorFunction(els));
12630         }else if(els.length !== undefined){
12631             this.addElements(els);
12632         }else{
12633             this.addElements([els]);
12634         }
12635         return this;
12636     },
12637     /**
12638     * Calls the passed function passing (el, this, index) for each element in this composite.
12639     * @param {Function} fn The function to call
12640     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12641     * @return {CompositeElement} this
12642     */
12643     each : function(fn, scope){
12644         var els = this.elements;
12645         for(var i = 0, len = els.length; i < len; i++){
12646             if(fn.call(scope || els[i], els[i], this, i) === false) {
12647                 break;
12648             }
12649         }
12650         return this;
12651     },
12652
12653     /**
12654      * Returns the Element object at the specified index
12655      * @param {Number} index
12656      * @return {Roo.Element}
12657      */
12658     item : function(index){
12659         return this.elements[index] || null;
12660     },
12661
12662     /**
12663      * Returns the first Element
12664      * @return {Roo.Element}
12665      */
12666     first : function(){
12667         return this.item(0);
12668     },
12669
12670     /**
12671      * Returns the last Element
12672      * @return {Roo.Element}
12673      */
12674     last : function(){
12675         return this.item(this.elements.length-1);
12676     },
12677
12678     /**
12679      * Returns the number of elements in this composite
12680      * @return Number
12681      */
12682     getCount : function(){
12683         return this.elements.length;
12684     },
12685
12686     /**
12687      * Returns true if this composite contains the passed element
12688      * @return Boolean
12689      */
12690     contains : function(el){
12691         return this.indexOf(el) !== -1;
12692     },
12693
12694     /**
12695      * Returns true if this composite contains the passed element
12696      * @return Boolean
12697      */
12698     indexOf : function(el){
12699         return this.elements.indexOf(Roo.get(el));
12700     },
12701
12702
12703     /**
12704     * Removes the specified element(s).
12705     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12706     * or an array of any of those.
12707     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12708     * @return {CompositeElement} this
12709     */
12710     removeElement : function(el, removeDom){
12711         if(el instanceof Array){
12712             for(var i = 0, len = el.length; i < len; i++){
12713                 this.removeElement(el[i]);
12714             }
12715             return this;
12716         }
12717         var index = typeof el == 'number' ? el : this.indexOf(el);
12718         if(index !== -1){
12719             if(removeDom){
12720                 var d = this.elements[index];
12721                 if(d.dom){
12722                     d.remove();
12723                 }else{
12724                     d.parentNode.removeChild(d);
12725                 }
12726             }
12727             this.elements.splice(index, 1);
12728         }
12729         return this;
12730     },
12731
12732     /**
12733     * Replaces the specified element with the passed element.
12734     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12735     * to replace.
12736     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12737     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12738     * @return {CompositeElement} this
12739     */
12740     replaceElement : function(el, replacement, domReplace){
12741         var index = typeof el == 'number' ? el : this.indexOf(el);
12742         if(index !== -1){
12743             if(domReplace){
12744                 this.elements[index].replaceWith(replacement);
12745             }else{
12746                 this.elements.splice(index, 1, Roo.get(replacement))
12747             }
12748         }
12749         return this;
12750     },
12751
12752     /**
12753      * Removes all elements.
12754      */
12755     clear : function(){
12756         this.elements = [];
12757     }
12758 };
12759 (function(){
12760     Roo.CompositeElement.createCall = function(proto, fnName){
12761         if(!proto[fnName]){
12762             proto[fnName] = function(){
12763                 return this.invoke(fnName, arguments);
12764             };
12765         }
12766     };
12767     for(var fnName in Roo.Element.prototype){
12768         if(typeof Roo.Element.prototype[fnName] == "function"){
12769             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12770         }
12771     };
12772 })();
12773 /*
12774  * Based on:
12775  * Ext JS Library 1.1.1
12776  * Copyright(c) 2006-2007, Ext JS, LLC.
12777  *
12778  * Originally Released Under LGPL - original licence link has changed is not relivant.
12779  *
12780  * Fork - LGPL
12781  * <script type="text/javascript">
12782  */
12783
12784 /**
12785  * @class Roo.CompositeElementLite
12786  * @extends Roo.CompositeElement
12787  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12788  <pre><code>
12789  var els = Roo.select("#some-el div.some-class");
12790  // or select directly from an existing element
12791  var el = Roo.get('some-el');
12792  el.select('div.some-class');
12793
12794  els.setWidth(100); // all elements become 100 width
12795  els.hide(true); // all elements fade out and hide
12796  // or
12797  els.setWidth(100).hide(true);
12798  </code></pre><br><br>
12799  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12800  * actions will be performed on all the elements in this collection.</b>
12801  */
12802 Roo.CompositeElementLite = function(els){
12803     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12804     this.el = new Roo.Element.Flyweight();
12805 };
12806 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12807     addElements : function(els){
12808         if(els){
12809             if(els instanceof Array){
12810                 this.elements = this.elements.concat(els);
12811             }else{
12812                 var yels = this.elements;
12813                 var index = yels.length-1;
12814                 for(var i = 0, len = els.length; i < len; i++) {
12815                     yels[++index] = els[i];
12816                 }
12817             }
12818         }
12819         return this;
12820     },
12821     invoke : function(fn, args){
12822         var els = this.elements;
12823         var el = this.el;
12824         for(var i = 0, len = els.length; i < len; i++) {
12825             el.dom = els[i];
12826                 Roo.Element.prototype[fn].apply(el, args);
12827         }
12828         return this;
12829     },
12830     /**
12831      * Returns a flyweight Element of the dom element object at the specified index
12832      * @param {Number} index
12833      * @return {Roo.Element}
12834      */
12835     item : function(index){
12836         if(!this.elements[index]){
12837             return null;
12838         }
12839         this.el.dom = this.elements[index];
12840         return this.el;
12841     },
12842
12843     // fixes scope with flyweight
12844     addListener : function(eventName, handler, scope, opt){
12845         var els = this.elements;
12846         for(var i = 0, len = els.length; i < len; i++) {
12847             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12848         }
12849         return this;
12850     },
12851
12852     /**
12853     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12854     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12855     * a reference to the dom node, use el.dom.</b>
12856     * @param {Function} fn The function to call
12857     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12858     * @return {CompositeElement} this
12859     */
12860     each : function(fn, scope){
12861         var els = this.elements;
12862         var el = this.el;
12863         for(var i = 0, len = els.length; i < len; i++){
12864             el.dom = els[i];
12865                 if(fn.call(scope || el, el, this, i) === false){
12866                 break;
12867             }
12868         }
12869         return this;
12870     },
12871
12872     indexOf : function(el){
12873         return this.elements.indexOf(Roo.getDom(el));
12874     },
12875
12876     replaceElement : function(el, replacement, domReplace){
12877         var index = typeof el == 'number' ? el : this.indexOf(el);
12878         if(index !== -1){
12879             replacement = Roo.getDom(replacement);
12880             if(domReplace){
12881                 var d = this.elements[index];
12882                 d.parentNode.insertBefore(replacement, d);
12883                 d.parentNode.removeChild(d);
12884             }
12885             this.elements.splice(index, 1, replacement);
12886         }
12887         return this;
12888     }
12889 });
12890 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12891
12892 /*
12893  * Based on:
12894  * Ext JS Library 1.1.1
12895  * Copyright(c) 2006-2007, Ext JS, LLC.
12896  *
12897  * Originally Released Under LGPL - original licence link has changed is not relivant.
12898  *
12899  * Fork - LGPL
12900  * <script type="text/javascript">
12901  */
12902
12903  
12904
12905 /**
12906  * @class Roo.data.Connection
12907  * @extends Roo.util.Observable
12908  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12909  * either to a configured URL, or to a URL specified at request time. 
12910  * 
12911  * Requests made by this class are asynchronous, and will return immediately. No data from
12912  * the server will be available to the statement immediately following the {@link #request} call.
12913  * To process returned data, use a callback in the request options object, or an event listener.
12914  * 
12915  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12916  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12917  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12918  * property and, if present, the IFRAME's XML document as the responseXML property.
12919  * 
12920  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12921  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12922  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12923  * standard DOM methods.
12924  * @constructor
12925  * @param {Object} config a configuration object.
12926  */
12927 Roo.data.Connection = function(config){
12928     Roo.apply(this, config);
12929     this.addEvents({
12930         /**
12931          * @event beforerequest
12932          * Fires before a network request is made to retrieve a data object.
12933          * @param {Connection} conn This Connection object.
12934          * @param {Object} options The options config object passed to the {@link #request} method.
12935          */
12936         "beforerequest" : true,
12937         /**
12938          * @event requestcomplete
12939          * Fires if the request was successfully completed.
12940          * @param {Connection} conn This Connection object.
12941          * @param {Object} response The XHR object containing the response data.
12942          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12943          * @param {Object} options The options config object passed to the {@link #request} method.
12944          */
12945         "requestcomplete" : true,
12946         /**
12947          * @event requestexception
12948          * Fires if an error HTTP status was returned from the server.
12949          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12950          * @param {Connection} conn This Connection object.
12951          * @param {Object} response The XHR object containing the response data.
12952          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12953          * @param {Object} options The options config object passed to the {@link #request} method.
12954          */
12955         "requestexception" : true
12956     });
12957     Roo.data.Connection.superclass.constructor.call(this);
12958 };
12959
12960 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12961     /**
12962      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12963      */
12964     /**
12965      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12966      * extra parameters to each request made by this object. (defaults to undefined)
12967      */
12968     /**
12969      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12970      *  to each request made by this object. (defaults to undefined)
12971      */
12972     /**
12973      * @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)
12974      */
12975     /**
12976      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12977      */
12978     timeout : 30000,
12979     /**
12980      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12981      * @type Boolean
12982      */
12983     autoAbort:false,
12984
12985     /**
12986      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12987      * @type Boolean
12988      */
12989     disableCaching: true,
12990
12991     /**
12992      * Sends an HTTP request to a remote server.
12993      * @param {Object} options An object which may contain the following properties:<ul>
12994      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12995      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12996      * request, a url encoded string or a function to call to get either.</li>
12997      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12998      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12999      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13000      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13001      * <li>options {Object} The parameter to the request call.</li>
13002      * <li>success {Boolean} True if the request succeeded.</li>
13003      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13004      * </ul></li>
13005      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13006      * The callback is passed the following parameters:<ul>
13007      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13008      * <li>options {Object} The parameter to the request call.</li>
13009      * </ul></li>
13010      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13011      * The callback is passed the following parameters:<ul>
13012      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13013      * <li>options {Object} The parameter to the request call.</li>
13014      * </ul></li>
13015      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13016      * for the callback function. Defaults to the browser window.</li>
13017      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13018      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13019      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13020      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13021      * params for the post data. Any params will be appended to the URL.</li>
13022      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13023      * </ul>
13024      * @return {Number} transactionId
13025      */
13026     request : function(o){
13027         if(this.fireEvent("beforerequest", this, o) !== false){
13028             var p = o.params;
13029
13030             if(typeof p == "function"){
13031                 p = p.call(o.scope||window, o);
13032             }
13033             if(typeof p == "object"){
13034                 p = Roo.urlEncode(o.params);
13035             }
13036             if(this.extraParams){
13037                 var extras = Roo.urlEncode(this.extraParams);
13038                 p = p ? (p + '&' + extras) : extras;
13039             }
13040
13041             var url = o.url || this.url;
13042             if(typeof url == 'function'){
13043                 url = url.call(o.scope||window, o);
13044             }
13045
13046             if(o.form){
13047                 var form = Roo.getDom(o.form);
13048                 url = url || form.action;
13049
13050                 var enctype = form.getAttribute("enctype");
13051                 
13052                 if (o.formData) {
13053                     return this.doFormDataUpload(o, url);
13054                 }
13055                 
13056                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13057                     return this.doFormUpload(o, p, url);
13058                 }
13059                 var f = Roo.lib.Ajax.serializeForm(form);
13060                 p = p ? (p + '&' + f) : f;
13061             }
13062             
13063             if (!o.form && o.formData) {
13064                 o.formData = o.formData === true ? new FormData() : o.formData;
13065                 for (var k in o.params) {
13066                     o.formData.append(k,o.params[k]);
13067                 }
13068                     
13069                 return this.doFormDataUpload(o, url);
13070             }
13071             
13072
13073             var hs = o.headers;
13074             if(this.defaultHeaders){
13075                 hs = Roo.apply(hs || {}, this.defaultHeaders);
13076                 if(!o.headers){
13077                     o.headers = hs;
13078                 }
13079             }
13080
13081             var cb = {
13082                 success: this.handleResponse,
13083                 failure: this.handleFailure,
13084                 scope: this,
13085                 argument: {options: o},
13086                 timeout : o.timeout || this.timeout
13087             };
13088
13089             var method = o.method||this.method||(p ? "POST" : "GET");
13090
13091             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13092                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13093             }
13094
13095             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13096                 if(o.autoAbort){
13097                     this.abort();
13098                 }
13099             }else if(this.autoAbort !== false){
13100                 this.abort();
13101             }
13102
13103             if((method == 'GET' && p) || o.xmlData){
13104                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13105                 p = '';
13106             }
13107             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13108             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13109             Roo.lib.Ajax.useDefaultHeader == true;
13110             return this.transId;
13111         }else{
13112             Roo.callback(o.callback, o.scope, [o, null, null]);
13113             return null;
13114         }
13115     },
13116
13117     /**
13118      * Determine whether this object has a request outstanding.
13119      * @param {Number} transactionId (Optional) defaults to the last transaction
13120      * @return {Boolean} True if there is an outstanding request.
13121      */
13122     isLoading : function(transId){
13123         if(transId){
13124             return Roo.lib.Ajax.isCallInProgress(transId);
13125         }else{
13126             return this.transId ? true : false;
13127         }
13128     },
13129
13130     /**
13131      * Aborts any outstanding request.
13132      * @param {Number} transactionId (Optional) defaults to the last transaction
13133      */
13134     abort : function(transId){
13135         if(transId || this.isLoading()){
13136             Roo.lib.Ajax.abort(transId || this.transId);
13137         }
13138     },
13139
13140     // private
13141     handleResponse : function(response){
13142         this.transId = false;
13143         var options = response.argument.options;
13144         response.argument = options ? options.argument : null;
13145         this.fireEvent("requestcomplete", this, response, options);
13146         Roo.callback(options.success, options.scope, [response, options]);
13147         Roo.callback(options.callback, options.scope, [options, true, response]);
13148     },
13149
13150     // private
13151     handleFailure : function(response, e){
13152         this.transId = false;
13153         var options = response.argument.options;
13154         response.argument = options ? options.argument : null;
13155         this.fireEvent("requestexception", this, response, options, e);
13156         Roo.callback(options.failure, options.scope, [response, options]);
13157         Roo.callback(options.callback, options.scope, [options, false, response]);
13158     },
13159
13160     // private
13161     doFormUpload : function(o, ps, url){
13162         var id = Roo.id();
13163         var frame = document.createElement('iframe');
13164         frame.id = id;
13165         frame.name = id;
13166         frame.className = 'x-hidden';
13167         if(Roo.isIE){
13168             frame.src = Roo.SSL_SECURE_URL;
13169         }
13170         document.body.appendChild(frame);
13171
13172         if(Roo.isIE){
13173            document.frames[id].name = id;
13174         }
13175
13176         var form = Roo.getDom(o.form);
13177         form.target = id;
13178         form.method = 'POST';
13179         form.enctype = form.encoding = 'multipart/form-data';
13180         if(url){
13181             form.action = url;
13182         }
13183
13184         var hiddens, hd;
13185         if(ps){ // add dynamic params
13186             hiddens = [];
13187             ps = Roo.urlDecode(ps, false);
13188             for(var k in ps){
13189                 if(ps.hasOwnProperty(k)){
13190                     hd = document.createElement('input');
13191                     hd.type = 'hidden';
13192                     hd.name = k;
13193                     hd.value = ps[k];
13194                     form.appendChild(hd);
13195                     hiddens.push(hd);
13196                 }
13197             }
13198         }
13199
13200         function cb(){
13201             var r = {  // bogus response object
13202                 responseText : '',
13203                 responseXML : null
13204             };
13205
13206             r.argument = o ? o.argument : null;
13207
13208             try { //
13209                 var doc;
13210                 if(Roo.isIE){
13211                     doc = frame.contentWindow.document;
13212                 }else {
13213                     doc = (frame.contentDocument || window.frames[id].document);
13214                 }
13215                 if(doc && doc.body){
13216                     r.responseText = doc.body.innerHTML;
13217                 }
13218                 if(doc && doc.XMLDocument){
13219                     r.responseXML = doc.XMLDocument;
13220                 }else {
13221                     r.responseXML = doc;
13222                 }
13223             }
13224             catch(e) {
13225                 // ignore
13226             }
13227
13228             Roo.EventManager.removeListener(frame, 'load', cb, this);
13229
13230             this.fireEvent("requestcomplete", this, r, o);
13231             Roo.callback(o.success, o.scope, [r, o]);
13232             Roo.callback(o.callback, o.scope, [o, true, r]);
13233
13234             setTimeout(function(){document.body.removeChild(frame);}, 100);
13235         }
13236
13237         Roo.EventManager.on(frame, 'load', cb, this);
13238         form.submit();
13239
13240         if(hiddens){ // remove dynamic params
13241             for(var i = 0, len = hiddens.length; i < len; i++){
13242                 form.removeChild(hiddens[i]);
13243             }
13244         }
13245     },
13246     // this is a 'formdata version???'
13247     
13248     
13249     doFormDataUpload : function(o,  url)
13250     {
13251         var formData;
13252         if (o.form) {
13253             var form =  Roo.getDom(o.form);
13254             form.enctype = form.encoding = 'multipart/form-data';
13255             formData = o.formData === true ? new FormData(form) : o.formData;
13256         } else {
13257             formData = o.formData === true ? new FormData() : o.formData;
13258         }
13259         
13260       
13261         var cb = {
13262             success: this.handleResponse,
13263             failure: this.handleFailure,
13264             scope: this,
13265             argument: {options: o},
13266             timeout : o.timeout || this.timeout
13267         };
13268  
13269         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13270             if(o.autoAbort){
13271                 this.abort();
13272             }
13273         }else if(this.autoAbort !== false){
13274             this.abort();
13275         }
13276
13277         //Roo.lib.Ajax.defaultPostHeader = null;
13278         Roo.lib.Ajax.useDefaultHeader = false;
13279         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13280         Roo.lib.Ajax.useDefaultHeader = true;
13281  
13282          
13283     }
13284     
13285 });
13286 /*
13287  * Based on:
13288  * Ext JS Library 1.1.1
13289  * Copyright(c) 2006-2007, Ext JS, LLC.
13290  *
13291  * Originally Released Under LGPL - original licence link has changed is not relivant.
13292  *
13293  * Fork - LGPL
13294  * <script type="text/javascript">
13295  */
13296  
13297 /**
13298  * Global Ajax request class.
13299  * 
13300  * @class Roo.Ajax
13301  * @extends Roo.data.Connection
13302  * @static
13303  * 
13304  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13305  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13306  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13307  * @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)
13308  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13309  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13310  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13311  */
13312 Roo.Ajax = new Roo.data.Connection({
13313     // fix up the docs
13314     /**
13315      * @scope Roo.Ajax
13316      * @type {Boolear} 
13317      */
13318     autoAbort : false,
13319
13320     /**
13321      * Serialize the passed form into a url encoded string
13322      * @scope Roo.Ajax
13323      * @param {String/HTMLElement} form
13324      * @return {String}
13325      */
13326     serializeForm : function(form){
13327         return Roo.lib.Ajax.serializeForm(form);
13328     }
13329 });/*
13330  * Based on:
13331  * Ext JS Library 1.1.1
13332  * Copyright(c) 2006-2007, Ext JS, LLC.
13333  *
13334  * Originally Released Under LGPL - original licence link has changed is not relivant.
13335  *
13336  * Fork - LGPL
13337  * <script type="text/javascript">
13338  */
13339
13340  
13341 /**
13342  * @class Roo.UpdateManager
13343  * @extends Roo.util.Observable
13344  * Provides AJAX-style update for Element object.<br><br>
13345  * Usage:<br>
13346  * <pre><code>
13347  * // Get it from a Roo.Element object
13348  * var el = Roo.get("foo");
13349  * var mgr = el.getUpdateManager();
13350  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13351  * ...
13352  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13353  * <br>
13354  * // or directly (returns the same UpdateManager instance)
13355  * var mgr = new Roo.UpdateManager("myElementId");
13356  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13357  * mgr.on("update", myFcnNeedsToKnow);
13358  * <br>
13359    // short handed call directly from the element object
13360    Roo.get("foo").load({
13361         url: "bar.php",
13362         scripts:true,
13363         params: "for=bar",
13364         text: "Loading Foo..."
13365    });
13366  * </code></pre>
13367  * @constructor
13368  * Create new UpdateManager directly.
13369  * @param {String/HTMLElement/Roo.Element} el The element to update
13370  * @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).
13371  */
13372 Roo.UpdateManager = function(el, forceNew){
13373     el = Roo.get(el);
13374     if(!forceNew && el.updateManager){
13375         return el.updateManager;
13376     }
13377     /**
13378      * The Element object
13379      * @type Roo.Element
13380      */
13381     this.el = el;
13382     /**
13383      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13384      * @type String
13385      */
13386     this.defaultUrl = null;
13387
13388     this.addEvents({
13389         /**
13390          * @event beforeupdate
13391          * Fired before an update is made, return false from your handler and the update is cancelled.
13392          * @param {Roo.Element} el
13393          * @param {String/Object/Function} url
13394          * @param {String/Object} params
13395          */
13396         "beforeupdate": true,
13397         /**
13398          * @event update
13399          * Fired after successful update is made.
13400          * @param {Roo.Element} el
13401          * @param {Object} oResponseObject The response Object
13402          */
13403         "update": true,
13404         /**
13405          * @event failure
13406          * Fired on update failure.
13407          * @param {Roo.Element} el
13408          * @param {Object} oResponseObject The response Object
13409          */
13410         "failure": true
13411     });
13412     var d = Roo.UpdateManager.defaults;
13413     /**
13414      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13415      * @type String
13416      */
13417     this.sslBlankUrl = d.sslBlankUrl;
13418     /**
13419      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13420      * @type Boolean
13421      */
13422     this.disableCaching = d.disableCaching;
13423     /**
13424      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13425      * @type String
13426      */
13427     this.indicatorText = d.indicatorText;
13428     /**
13429      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13430      * @type String
13431      */
13432     this.showLoadIndicator = d.showLoadIndicator;
13433     /**
13434      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13435      * @type Number
13436      */
13437     this.timeout = d.timeout;
13438
13439     /**
13440      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13441      * @type Boolean
13442      */
13443     this.loadScripts = d.loadScripts;
13444
13445     /**
13446      * Transaction object of current executing transaction
13447      */
13448     this.transaction = null;
13449
13450     /**
13451      * @private
13452      */
13453     this.autoRefreshProcId = null;
13454     /**
13455      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13456      * @type Function
13457      */
13458     this.refreshDelegate = this.refresh.createDelegate(this);
13459     /**
13460      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13461      * @type Function
13462      */
13463     this.updateDelegate = this.update.createDelegate(this);
13464     /**
13465      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13466      * @type Function
13467      */
13468     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13469     /**
13470      * @private
13471      */
13472     this.successDelegate = this.processSuccess.createDelegate(this);
13473     /**
13474      * @private
13475      */
13476     this.failureDelegate = this.processFailure.createDelegate(this);
13477
13478     if(!this.renderer){
13479      /**
13480       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13481       */
13482     this.renderer = new Roo.UpdateManager.BasicRenderer();
13483     }
13484     
13485     Roo.UpdateManager.superclass.constructor.call(this);
13486 };
13487
13488 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13489     /**
13490      * Get the Element this UpdateManager is bound to
13491      * @return {Roo.Element} The element
13492      */
13493     getEl : function(){
13494         return this.el;
13495     },
13496     /**
13497      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13498      * @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:
13499 <pre><code>
13500 um.update({<br/>
13501     url: "your-url.php",<br/>
13502     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13503     callback: yourFunction,<br/>
13504     scope: yourObject, //(optional scope)  <br/>
13505     discardUrl: false, <br/>
13506     nocache: false,<br/>
13507     text: "Loading...",<br/>
13508     timeout: 30,<br/>
13509     scripts: false<br/>
13510 });
13511 </code></pre>
13512      * The only required property is url. The optional properties nocache, text and scripts
13513      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13514      * @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}
13515      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13516      * @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.
13517      */
13518     update : function(url, params, callback, discardUrl){
13519         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13520             var method = this.method,
13521                 cfg;
13522             if(typeof url == "object"){ // must be config object
13523                 cfg = url;
13524                 url = cfg.url;
13525                 params = params || cfg.params;
13526                 callback = callback || cfg.callback;
13527                 discardUrl = discardUrl || cfg.discardUrl;
13528                 if(callback && cfg.scope){
13529                     callback = callback.createDelegate(cfg.scope);
13530                 }
13531                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13532                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13533                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13534                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13535                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13536             }
13537             this.showLoading();
13538             if(!discardUrl){
13539                 this.defaultUrl = url;
13540             }
13541             if(typeof url == "function"){
13542                 url = url.call(this);
13543             }
13544
13545             method = method || (params ? "POST" : "GET");
13546             if(method == "GET"){
13547                 url = this.prepareUrl(url);
13548             }
13549
13550             var o = Roo.apply(cfg ||{}, {
13551                 url : url,
13552                 params: params,
13553                 success: this.successDelegate,
13554                 failure: this.failureDelegate,
13555                 callback: undefined,
13556                 timeout: (this.timeout*1000),
13557                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13558             });
13559             Roo.log("updated manager called with timeout of " + o.timeout);
13560             this.transaction = Roo.Ajax.request(o);
13561         }
13562     },
13563
13564     /**
13565      * 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.
13566      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13567      * @param {String/HTMLElement} form The form Id or form element
13568      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13569      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13570      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13571      */
13572     formUpdate : function(form, url, reset, callback){
13573         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13574             if(typeof url == "function"){
13575                 url = url.call(this);
13576             }
13577             form = Roo.getDom(form);
13578             this.transaction = Roo.Ajax.request({
13579                 form: form,
13580                 url:url,
13581                 success: this.successDelegate,
13582                 failure: this.failureDelegate,
13583                 timeout: (this.timeout*1000),
13584                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13585             });
13586             this.showLoading.defer(1, this);
13587         }
13588     },
13589
13590     /**
13591      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13592      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13593      */
13594     refresh : function(callback){
13595         if(this.defaultUrl == null){
13596             return;
13597         }
13598         this.update(this.defaultUrl, null, callback, true);
13599     },
13600
13601     /**
13602      * Set this element to auto refresh.
13603      * @param {Number} interval How often to update (in seconds).
13604      * @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)
13605      * @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}
13606      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13607      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13608      */
13609     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13610         if(refreshNow){
13611             this.update(url || this.defaultUrl, params, callback, true);
13612         }
13613         if(this.autoRefreshProcId){
13614             clearInterval(this.autoRefreshProcId);
13615         }
13616         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13617     },
13618
13619     /**
13620      * Stop auto refresh on this element.
13621      */
13622      stopAutoRefresh : function(){
13623         if(this.autoRefreshProcId){
13624             clearInterval(this.autoRefreshProcId);
13625             delete this.autoRefreshProcId;
13626         }
13627     },
13628
13629     isAutoRefreshing : function(){
13630        return this.autoRefreshProcId ? true : false;
13631     },
13632     /**
13633      * Called to update the element to "Loading" state. Override to perform custom action.
13634      */
13635     showLoading : function(){
13636         if(this.showLoadIndicator){
13637             this.el.update(this.indicatorText);
13638         }
13639     },
13640
13641     /**
13642      * Adds unique parameter to query string if disableCaching = true
13643      * @private
13644      */
13645     prepareUrl : function(url){
13646         if(this.disableCaching){
13647             var append = "_dc=" + (new Date().getTime());
13648             if(url.indexOf("?") !== -1){
13649                 url += "&" + append;
13650             }else{
13651                 url += "?" + append;
13652             }
13653         }
13654         return url;
13655     },
13656
13657     /**
13658      * @private
13659      */
13660     processSuccess : function(response){
13661         this.transaction = null;
13662         if(response.argument.form && response.argument.reset){
13663             try{ // put in try/catch since some older FF releases had problems with this
13664                 response.argument.form.reset();
13665             }catch(e){}
13666         }
13667         if(this.loadScripts){
13668             this.renderer.render(this.el, response, this,
13669                 this.updateComplete.createDelegate(this, [response]));
13670         }else{
13671             this.renderer.render(this.el, response, this);
13672             this.updateComplete(response);
13673         }
13674     },
13675
13676     updateComplete : function(response){
13677         this.fireEvent("update", this.el, response);
13678         if(typeof response.argument.callback == "function"){
13679             response.argument.callback(this.el, true, response);
13680         }
13681     },
13682
13683     /**
13684      * @private
13685      */
13686     processFailure : function(response){
13687         this.transaction = null;
13688         this.fireEvent("failure", this.el, response);
13689         if(typeof response.argument.callback == "function"){
13690             response.argument.callback(this.el, false, response);
13691         }
13692     },
13693
13694     /**
13695      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13696      * @param {Object} renderer The object implementing the render() method
13697      */
13698     setRenderer : function(renderer){
13699         this.renderer = renderer;
13700     },
13701
13702     getRenderer : function(){
13703        return this.renderer;
13704     },
13705
13706     /**
13707      * Set the defaultUrl used for updates
13708      * @param {String/Function} defaultUrl The url or a function to call to get the url
13709      */
13710     setDefaultUrl : function(defaultUrl){
13711         this.defaultUrl = defaultUrl;
13712     },
13713
13714     /**
13715      * Aborts the executing transaction
13716      */
13717     abort : function(){
13718         if(this.transaction){
13719             Roo.Ajax.abort(this.transaction);
13720         }
13721     },
13722
13723     /**
13724      * Returns true if an update is in progress
13725      * @return {Boolean}
13726      */
13727     isUpdating : function(){
13728         if(this.transaction){
13729             return Roo.Ajax.isLoading(this.transaction);
13730         }
13731         return false;
13732     }
13733 });
13734
13735 /**
13736  * @class Roo.UpdateManager.defaults
13737  * @static (not really - but it helps the doc tool)
13738  * The defaults collection enables customizing the default properties of UpdateManager
13739  */
13740    Roo.UpdateManager.defaults = {
13741        /**
13742          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13743          * @type Number
13744          */
13745          timeout : 30,
13746
13747          /**
13748          * True to process scripts by default (Defaults to false).
13749          * @type Boolean
13750          */
13751         loadScripts : false,
13752
13753         /**
13754         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13755         * @type String
13756         */
13757         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13758         /**
13759          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13760          * @type Boolean
13761          */
13762         disableCaching : false,
13763         /**
13764          * Whether to show indicatorText when loading (Defaults to true).
13765          * @type Boolean
13766          */
13767         showLoadIndicator : true,
13768         /**
13769          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13770          * @type String
13771          */
13772         indicatorText : '<div class="loading-indicator">Loading...</div>'
13773    };
13774
13775 /**
13776  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13777  *Usage:
13778  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13779  * @param {String/HTMLElement/Roo.Element} el The element to update
13780  * @param {String} url The url
13781  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13782  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13783  * @static
13784  * @deprecated
13785  * @member Roo.UpdateManager
13786  */
13787 Roo.UpdateManager.updateElement = function(el, url, params, options){
13788     var um = Roo.get(el, true).getUpdateManager();
13789     Roo.apply(um, options);
13790     um.update(url, params, options ? options.callback : null);
13791 };
13792 // alias for backwards compat
13793 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13794 /**
13795  * @class Roo.UpdateManager.BasicRenderer
13796  * Default Content renderer. Updates the elements innerHTML with the responseText.
13797  */
13798 Roo.UpdateManager.BasicRenderer = function(){};
13799
13800 Roo.UpdateManager.BasicRenderer.prototype = {
13801     /**
13802      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13803      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13804      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13805      * @param {Roo.Element} el The element being rendered
13806      * @param {Object} response The YUI Connect response object
13807      * @param {UpdateManager} updateManager The calling update manager
13808      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13809      */
13810      render : function(el, response, updateManager, callback){
13811         el.update(response.responseText, updateManager.loadScripts, callback);
13812     }
13813 };
13814 /*
13815  * Based on:
13816  * Roo JS
13817  * (c)) Alan Knowles
13818  * Licence : LGPL
13819  */
13820
13821
13822 /**
13823  * @class Roo.DomTemplate
13824  * @extends Roo.Template
13825  * An effort at a dom based template engine..
13826  *
13827  * Similar to XTemplate, except it uses dom parsing to create the template..
13828  *
13829  * Supported features:
13830  *
13831  *  Tags:
13832
13833 <pre><code>
13834       {a_variable} - output encoded.
13835       {a_variable.format:("Y-m-d")} - call a method on the variable
13836       {a_variable:raw} - unencoded output
13837       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13838       {a_variable:this.method_on_template(...)} - call a method on the template object.
13839  
13840 </code></pre>
13841  *  The tpl tag:
13842 <pre><code>
13843         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13844         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13845         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13846         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13847   
13848 </code></pre>
13849  *      
13850  */
13851 Roo.DomTemplate = function()
13852 {
13853      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13854      if (this.html) {
13855         this.compile();
13856      }
13857 };
13858
13859
13860 Roo.extend(Roo.DomTemplate, Roo.Template, {
13861     /**
13862      * id counter for sub templates.
13863      */
13864     id : 0,
13865     /**
13866      * flag to indicate if dom parser is inside a pre,
13867      * it will strip whitespace if not.
13868      */
13869     inPre : false,
13870     
13871     /**
13872      * The various sub templates
13873      */
13874     tpls : false,
13875     
13876     
13877     
13878     /**
13879      *
13880      * basic tag replacing syntax
13881      * WORD:WORD()
13882      *
13883      * // you can fake an object call by doing this
13884      *  x.t:(test,tesT) 
13885      * 
13886      */
13887     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13888     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13889     
13890     iterChild : function (node, method) {
13891         
13892         var oldPre = this.inPre;
13893         if (node.tagName == 'PRE') {
13894             this.inPre = true;
13895         }
13896         for( var i = 0; i < node.childNodes.length; i++) {
13897             method.call(this, node.childNodes[i]);
13898         }
13899         this.inPre = oldPre;
13900     },
13901     
13902     
13903     
13904     /**
13905      * compile the template
13906      *
13907      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13908      *
13909      */
13910     compile: function()
13911     {
13912         var s = this.html;
13913         
13914         // covert the html into DOM...
13915         var doc = false;
13916         var div =false;
13917         try {
13918             doc = document.implementation.createHTMLDocument("");
13919             doc.documentElement.innerHTML =   this.html  ;
13920             div = doc.documentElement;
13921         } catch (e) {
13922             // old IE... - nasty -- it causes all sorts of issues.. with
13923             // images getting pulled from server..
13924             div = document.createElement('div');
13925             div.innerHTML = this.html;
13926         }
13927         //doc.documentElement.innerHTML = htmlBody
13928          
13929         
13930         
13931         this.tpls = [];
13932         var _t = this;
13933         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13934         
13935         var tpls = this.tpls;
13936         
13937         // create a top level template from the snippet..
13938         
13939         //Roo.log(div.innerHTML);
13940         
13941         var tpl = {
13942             uid : 'master',
13943             id : this.id++,
13944             attr : false,
13945             value : false,
13946             body : div.innerHTML,
13947             
13948             forCall : false,
13949             execCall : false,
13950             dom : div,
13951             isTop : true
13952             
13953         };
13954         tpls.unshift(tpl);
13955         
13956         
13957         // compile them...
13958         this.tpls = [];
13959         Roo.each(tpls, function(tp){
13960             this.compileTpl(tp);
13961             this.tpls[tp.id] = tp;
13962         }, this);
13963         
13964         this.master = tpls[0];
13965         return this;
13966         
13967         
13968     },
13969     
13970     compileNode : function(node, istop) {
13971         // test for
13972         //Roo.log(node);
13973         
13974         
13975         // skip anything not a tag..
13976         if (node.nodeType != 1) {
13977             if (node.nodeType == 3 && !this.inPre) {
13978                 // reduce white space..
13979                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13980                 
13981             }
13982             return;
13983         }
13984         
13985         var tpl = {
13986             uid : false,
13987             id : false,
13988             attr : false,
13989             value : false,
13990             body : '',
13991             
13992             forCall : false,
13993             execCall : false,
13994             dom : false,
13995             isTop : istop
13996             
13997             
13998         };
13999         
14000         
14001         switch(true) {
14002             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14003             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14004             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14005             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14006             // no default..
14007         }
14008         
14009         
14010         if (!tpl.attr) {
14011             // just itterate children..
14012             this.iterChild(node,this.compileNode);
14013             return;
14014         }
14015         tpl.uid = this.id++;
14016         tpl.value = node.getAttribute('roo-' +  tpl.attr);
14017         node.removeAttribute('roo-'+ tpl.attr);
14018         if (tpl.attr != 'name') {
14019             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14020             node.parentNode.replaceChild(placeholder,  node);
14021         } else {
14022             
14023             var placeholder =  document.createElement('span');
14024             placeholder.className = 'roo-tpl-' + tpl.value;
14025             node.parentNode.replaceChild(placeholder,  node);
14026         }
14027         
14028         // parent now sees '{domtplXXXX}
14029         this.iterChild(node,this.compileNode);
14030         
14031         // we should now have node body...
14032         var div = document.createElement('div');
14033         div.appendChild(node);
14034         tpl.dom = node;
14035         // this has the unfortunate side effect of converting tagged attributes
14036         // eg. href="{...}" into %7C...%7D
14037         // this has been fixed by searching for those combo's although it's a bit hacky..
14038         
14039         
14040         tpl.body = div.innerHTML;
14041         
14042         
14043          
14044         tpl.id = tpl.uid;
14045         switch(tpl.attr) {
14046             case 'for' :
14047                 switch (tpl.value) {
14048                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14049                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14050                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14051                 }
14052                 break;
14053             
14054             case 'exec':
14055                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14056                 break;
14057             
14058             case 'if':     
14059                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14060                 break;
14061             
14062             case 'name':
14063                 tpl.id  = tpl.value; // replace non characters???
14064                 break;
14065             
14066         }
14067         
14068         
14069         this.tpls.push(tpl);
14070         
14071         
14072         
14073     },
14074     
14075     
14076     
14077     
14078     /**
14079      * Compile a segment of the template into a 'sub-template'
14080      *
14081      * 
14082      * 
14083      *
14084      */
14085     compileTpl : function(tpl)
14086     {
14087         var fm = Roo.util.Format;
14088         var useF = this.disableFormats !== true;
14089         
14090         var sep = Roo.isGecko ? "+\n" : ",\n";
14091         
14092         var undef = function(str) {
14093             Roo.debug && Roo.log("Property not found :"  + str);
14094             return '';
14095         };
14096           
14097         //Roo.log(tpl.body);
14098         
14099         
14100         
14101         var fn = function(m, lbrace, name, format, args)
14102         {
14103             //Roo.log("ARGS");
14104             //Roo.log(arguments);
14105             args = args ? args.replace(/\\'/g,"'") : args;
14106             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14107             if (typeof(format) == 'undefined') {
14108                 format =  'htmlEncode'; 
14109             }
14110             if (format == 'raw' ) {
14111                 format = false;
14112             }
14113             
14114             if(name.substr(0, 6) == 'domtpl'){
14115                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14116             }
14117             
14118             // build an array of options to determine if value is undefined..
14119             
14120             // basically get 'xxxx.yyyy' then do
14121             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14122             //    (function () { Roo.log("Property not found"); return ''; })() :
14123             //    ......
14124             
14125             var udef_ar = [];
14126             var lookfor = '';
14127             Roo.each(name.split('.'), function(st) {
14128                 lookfor += (lookfor.length ? '.': '') + st;
14129                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
14130             });
14131             
14132             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14133             
14134             
14135             if(format && useF){
14136                 
14137                 args = args ? ',' + args : "";
14138                  
14139                 if(format.substr(0, 5) != "this."){
14140                     format = "fm." + format + '(';
14141                 }else{
14142                     format = 'this.call("'+ format.substr(5) + '", ';
14143                     args = ", values";
14144                 }
14145                 
14146                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
14147             }
14148              
14149             if (args && args.length) {
14150                 // called with xxyx.yuu:(test,test)
14151                 // change to ()
14152                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
14153             }
14154             // raw.. - :raw modifier..
14155             return "'"+ sep + udef_st  + name + ")"+sep+"'";
14156             
14157         };
14158         var body;
14159         // branched to use + in gecko and [].join() in others
14160         if(Roo.isGecko){
14161             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
14162                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14163                     "';};};";
14164         }else{
14165             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
14166             body.push(tpl.body.replace(/(\r\n|\n)/g,
14167                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14168             body.push("'].join('');};};");
14169             body = body.join('');
14170         }
14171         
14172         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14173        
14174         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
14175         eval(body);
14176         
14177         return this;
14178     },
14179      
14180     /**
14181      * same as applyTemplate, except it's done to one of the subTemplates
14182      * when using named templates, you can do:
14183      *
14184      * var str = pl.applySubTemplate('your-name', values);
14185      *
14186      * 
14187      * @param {Number} id of the template
14188      * @param {Object} values to apply to template
14189      * @param {Object} parent (normaly the instance of this object)
14190      */
14191     applySubTemplate : function(id, values, parent)
14192     {
14193         
14194         
14195         var t = this.tpls[id];
14196         
14197         
14198         try { 
14199             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14200                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14201                 return '';
14202             }
14203         } catch(e) {
14204             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14205             Roo.log(values);
14206           
14207             return '';
14208         }
14209         try { 
14210             
14211             if(t.execCall && t.execCall.call(this, values, parent)){
14212                 return '';
14213             }
14214         } catch(e) {
14215             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14216             Roo.log(values);
14217             return '';
14218         }
14219         
14220         try {
14221             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14222             parent = t.target ? values : parent;
14223             if(t.forCall && vs instanceof Array){
14224                 var buf = [];
14225                 for(var i = 0, len = vs.length; i < len; i++){
14226                     try {
14227                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14228                     } catch (e) {
14229                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14230                         Roo.log(e.body);
14231                         //Roo.log(t.compiled);
14232                         Roo.log(vs[i]);
14233                     }   
14234                 }
14235                 return buf.join('');
14236             }
14237         } catch (e) {
14238             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14239             Roo.log(values);
14240             return '';
14241         }
14242         try {
14243             return t.compiled.call(this, vs, parent);
14244         } catch (e) {
14245             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14246             Roo.log(e.body);
14247             //Roo.log(t.compiled);
14248             Roo.log(values);
14249             return '';
14250         }
14251     },
14252
14253    
14254
14255     applyTemplate : function(values){
14256         return this.master.compiled.call(this, values, {});
14257         //var s = this.subs;
14258     },
14259
14260     apply : function(){
14261         return this.applyTemplate.apply(this, arguments);
14262     }
14263
14264  });
14265
14266 Roo.DomTemplate.from = function(el){
14267     el = Roo.getDom(el);
14268     return new Roo.Domtemplate(el.value || el.innerHTML);
14269 };/*
14270  * Based on:
14271  * Ext JS Library 1.1.1
14272  * Copyright(c) 2006-2007, Ext JS, LLC.
14273  *
14274  * Originally Released Under LGPL - original licence link has changed is not relivant.
14275  *
14276  * Fork - LGPL
14277  * <script type="text/javascript">
14278  */
14279
14280 /**
14281  * @class Roo.util.DelayedTask
14282  * Provides a convenient method of performing setTimeout where a new
14283  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14284  * You can use this class to buffer
14285  * the keypress events for a certain number of milliseconds, and perform only if they stop
14286  * for that amount of time.
14287  * @constructor The parameters to this constructor serve as defaults and are not required.
14288  * @param {Function} fn (optional) The default function to timeout
14289  * @param {Object} scope (optional) The default scope of that timeout
14290  * @param {Array} args (optional) The default Array of arguments
14291  */
14292 Roo.util.DelayedTask = function(fn, scope, args){
14293     var id = null, d, t;
14294
14295     var call = function(){
14296         var now = new Date().getTime();
14297         if(now - t >= d){
14298             clearInterval(id);
14299             id = null;
14300             fn.apply(scope, args || []);
14301         }
14302     };
14303     /**
14304      * Cancels any pending timeout and queues a new one
14305      * @param {Number} delay The milliseconds to delay
14306      * @param {Function} newFn (optional) Overrides function passed to constructor
14307      * @param {Object} newScope (optional) Overrides scope passed to constructor
14308      * @param {Array} newArgs (optional) Overrides args passed to constructor
14309      */
14310     this.delay = function(delay, newFn, newScope, newArgs){
14311         if(id && delay != d){
14312             this.cancel();
14313         }
14314         d = delay;
14315         t = new Date().getTime();
14316         fn = newFn || fn;
14317         scope = newScope || scope;
14318         args = newArgs || args;
14319         if(!id){
14320             id = setInterval(call, d);
14321         }
14322     };
14323
14324     /**
14325      * Cancel the last queued timeout
14326      */
14327     this.cancel = function(){
14328         if(id){
14329             clearInterval(id);
14330             id = null;
14331         }
14332     };
14333 };/*
14334  * Based on:
14335  * Ext JS Library 1.1.1
14336  * Copyright(c) 2006-2007, Ext JS, LLC.
14337  *
14338  * Originally Released Under LGPL - original licence link has changed is not relivant.
14339  *
14340  * Fork - LGPL
14341  * <script type="text/javascript">
14342  */
14343 /**
14344  * @class Roo.util.TaskRunner
14345  * Manage background tasks - not sure why this is better that setInterval?
14346  * @static
14347  *
14348  */
14349  
14350 Roo.util.TaskRunner = function(interval){
14351     interval = interval || 10;
14352     var tasks = [], removeQueue = [];
14353     var id = 0;
14354     var running = false;
14355
14356     var stopThread = function(){
14357         running = false;
14358         clearInterval(id);
14359         id = 0;
14360     };
14361
14362     var startThread = function(){
14363         if(!running){
14364             running = true;
14365             id = setInterval(runTasks, interval);
14366         }
14367     };
14368
14369     var removeTask = function(task){
14370         removeQueue.push(task);
14371         if(task.onStop){
14372             task.onStop();
14373         }
14374     };
14375
14376     var runTasks = function(){
14377         if(removeQueue.length > 0){
14378             for(var i = 0, len = removeQueue.length; i < len; i++){
14379                 tasks.remove(removeQueue[i]);
14380             }
14381             removeQueue = [];
14382             if(tasks.length < 1){
14383                 stopThread();
14384                 return;
14385             }
14386         }
14387         var now = new Date().getTime();
14388         for(var i = 0, len = tasks.length; i < len; ++i){
14389             var t = tasks[i];
14390             var itime = now - t.taskRunTime;
14391             if(t.interval <= itime){
14392                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14393                 t.taskRunTime = now;
14394                 if(rt === false || t.taskRunCount === t.repeat){
14395                     removeTask(t);
14396                     return;
14397                 }
14398             }
14399             if(t.duration && t.duration <= (now - t.taskStartTime)){
14400                 removeTask(t);
14401             }
14402         }
14403     };
14404
14405     /**
14406      * Queues a new task.
14407      * @param {Object} task
14408      *
14409      * Task property : interval = how frequent to run.
14410      * Task object should implement
14411      * function run()
14412      * Task object may implement
14413      * function onStop()
14414      */
14415     this.start = function(task){
14416         tasks.push(task);
14417         task.taskStartTime = new Date().getTime();
14418         task.taskRunTime = 0;
14419         task.taskRunCount = 0;
14420         startThread();
14421         return task;
14422     };
14423     /**
14424      * Stop  new task.
14425      * @param {Object} task
14426      */
14427     this.stop = function(task){
14428         removeTask(task);
14429         return task;
14430     };
14431     /**
14432      * Stop all Tasks
14433      */
14434     this.stopAll = function(){
14435         stopThread();
14436         for(var i = 0, len = tasks.length; i < len; i++){
14437             if(tasks[i].onStop){
14438                 tasks[i].onStop();
14439             }
14440         }
14441         tasks = [];
14442         removeQueue = [];
14443     };
14444 };
14445
14446 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14447  * Based on:
14448  * Ext JS Library 1.1.1
14449  * Copyright(c) 2006-2007, Ext JS, LLC.
14450  *
14451  * Originally Released Under LGPL - original licence link has changed is not relivant.
14452  *
14453  * Fork - LGPL
14454  * <script type="text/javascript">
14455  */
14456
14457  
14458 /**
14459  * @class Roo.util.MixedCollection
14460  * @extends Roo.util.Observable
14461  * A Collection class that maintains both numeric indexes and keys and exposes events.
14462  * @constructor
14463  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14464  * collection (defaults to false)
14465  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14466  * and return the key value for that item.  This is used when available to look up the key on items that
14467  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14468  * equivalent to providing an implementation for the {@link #getKey} method.
14469  */
14470 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14471     this.items = [];
14472     this.map = {};
14473     this.keys = [];
14474     this.length = 0;
14475     this.addEvents({
14476         /**
14477          * @event clear
14478          * Fires when the collection is cleared.
14479          */
14480         "clear" : true,
14481         /**
14482          * @event add
14483          * Fires when an item is added to the collection.
14484          * @param {Number} index The index at which the item was added.
14485          * @param {Object} o The item added.
14486          * @param {String} key The key associated with the added item.
14487          */
14488         "add" : true,
14489         /**
14490          * @event replace
14491          * Fires when an item is replaced in the collection.
14492          * @param {String} key he key associated with the new added.
14493          * @param {Object} old The item being replaced.
14494          * @param {Object} new The new item.
14495          */
14496         "replace" : true,
14497         /**
14498          * @event remove
14499          * Fires when an item is removed from the collection.
14500          * @param {Object} o The item being removed.
14501          * @param {String} key (optional) The key associated with the removed item.
14502          */
14503         "remove" : true,
14504         "sort" : true
14505     });
14506     this.allowFunctions = allowFunctions === true;
14507     if(keyFn){
14508         this.getKey = keyFn;
14509     }
14510     Roo.util.MixedCollection.superclass.constructor.call(this);
14511 };
14512
14513 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14514     allowFunctions : false,
14515     
14516 /**
14517  * Adds an item to the collection.
14518  * @param {String} key The key to associate with the item
14519  * @param {Object} o The item to add.
14520  * @return {Object} The item added.
14521  */
14522     add : function(key, o){
14523         if(arguments.length == 1){
14524             o = arguments[0];
14525             key = this.getKey(o);
14526         }
14527         if(typeof key == "undefined" || key === null){
14528             this.length++;
14529             this.items.push(o);
14530             this.keys.push(null);
14531         }else{
14532             var old = this.map[key];
14533             if(old){
14534                 return this.replace(key, o);
14535             }
14536             this.length++;
14537             this.items.push(o);
14538             this.map[key] = o;
14539             this.keys.push(key);
14540         }
14541         this.fireEvent("add", this.length-1, o, key);
14542         return o;
14543     },
14544        
14545 /**
14546   * MixedCollection has a generic way to fetch keys if you implement getKey.
14547 <pre><code>
14548 // normal way
14549 var mc = new Roo.util.MixedCollection();
14550 mc.add(someEl.dom.id, someEl);
14551 mc.add(otherEl.dom.id, otherEl);
14552 //and so on
14553
14554 // using getKey
14555 var mc = new Roo.util.MixedCollection();
14556 mc.getKey = function(el){
14557    return el.dom.id;
14558 };
14559 mc.add(someEl);
14560 mc.add(otherEl);
14561
14562 // or via the constructor
14563 var mc = new Roo.util.MixedCollection(false, function(el){
14564    return el.dom.id;
14565 });
14566 mc.add(someEl);
14567 mc.add(otherEl);
14568 </code></pre>
14569  * @param o {Object} The item for which to find the key.
14570  * @return {Object} The key for the passed item.
14571  */
14572     getKey : function(o){
14573          return o.id; 
14574     },
14575    
14576 /**
14577  * Replaces an item in the collection.
14578  * @param {String} key The key associated with the item to replace, or the item to replace.
14579  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14580  * @return {Object}  The new item.
14581  */
14582     replace : function(key, o){
14583         if(arguments.length == 1){
14584             o = arguments[0];
14585             key = this.getKey(o);
14586         }
14587         var old = this.item(key);
14588         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14589              return this.add(key, o);
14590         }
14591         var index = this.indexOfKey(key);
14592         this.items[index] = o;
14593         this.map[key] = o;
14594         this.fireEvent("replace", key, old, o);
14595         return o;
14596     },
14597    
14598 /**
14599  * Adds all elements of an Array or an Object to the collection.
14600  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14601  * an Array of values, each of which are added to the collection.
14602  */
14603     addAll : function(objs){
14604         if(arguments.length > 1 || objs instanceof Array){
14605             var args = arguments.length > 1 ? arguments : objs;
14606             for(var i = 0, len = args.length; i < len; i++){
14607                 this.add(args[i]);
14608             }
14609         }else{
14610             for(var key in objs){
14611                 if(this.allowFunctions || typeof objs[key] != "function"){
14612                     this.add(key, objs[key]);
14613                 }
14614             }
14615         }
14616     },
14617    
14618 /**
14619  * Executes the specified function once for every item in the collection, passing each
14620  * item as the first and only parameter. returning false from the function will stop the iteration.
14621  * @param {Function} fn The function to execute for each item.
14622  * @param {Object} scope (optional) The scope in which to execute the function.
14623  */
14624     each : function(fn, scope){
14625         var items = [].concat(this.items); // each safe for removal
14626         for(var i = 0, len = items.length; i < len; i++){
14627             if(fn.call(scope || items[i], items[i], i, len) === false){
14628                 break;
14629             }
14630         }
14631     },
14632    
14633 /**
14634  * Executes the specified function once for every key in the collection, passing each
14635  * key, and its associated item as the first two parameters.
14636  * @param {Function} fn The function to execute for each item.
14637  * @param {Object} scope (optional) The scope in which to execute the function.
14638  */
14639     eachKey : function(fn, scope){
14640         for(var i = 0, len = this.keys.length; i < len; i++){
14641             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14642         }
14643     },
14644    
14645 /**
14646  * Returns the first item in the collection which elicits a true return value from the
14647  * passed selection function.
14648  * @param {Function} fn The selection function to execute for each item.
14649  * @param {Object} scope (optional) The scope in which to execute the function.
14650  * @return {Object} The first item in the collection which returned true from the selection function.
14651  */
14652     find : function(fn, scope){
14653         for(var i = 0, len = this.items.length; i < len; i++){
14654             if(fn.call(scope || window, this.items[i], this.keys[i])){
14655                 return this.items[i];
14656             }
14657         }
14658         return null;
14659     },
14660    
14661 /**
14662  * Inserts an item at the specified index in the collection.
14663  * @param {Number} index The index to insert the item at.
14664  * @param {String} key The key to associate with the new item, or the item itself.
14665  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14666  * @return {Object} The item inserted.
14667  */
14668     insert : function(index, key, o){
14669         if(arguments.length == 2){
14670             o = arguments[1];
14671             key = this.getKey(o);
14672         }
14673         if(index >= this.length){
14674             return this.add(key, o);
14675         }
14676         this.length++;
14677         this.items.splice(index, 0, o);
14678         if(typeof key != "undefined" && key != null){
14679             this.map[key] = o;
14680         }
14681         this.keys.splice(index, 0, key);
14682         this.fireEvent("add", index, o, key);
14683         return o;
14684     },
14685    
14686 /**
14687  * Removed an item from the collection.
14688  * @param {Object} o The item to remove.
14689  * @return {Object} The item removed.
14690  */
14691     remove : function(o){
14692         return this.removeAt(this.indexOf(o));
14693     },
14694    
14695 /**
14696  * Remove an item from a specified index in the collection.
14697  * @param {Number} index The index within the collection of the item to remove.
14698  */
14699     removeAt : function(index){
14700         if(index < this.length && index >= 0){
14701             this.length--;
14702             var o = this.items[index];
14703             this.items.splice(index, 1);
14704             var key = this.keys[index];
14705             if(typeof key != "undefined"){
14706                 delete this.map[key];
14707             }
14708             this.keys.splice(index, 1);
14709             this.fireEvent("remove", o, key);
14710         }
14711     },
14712    
14713 /**
14714  * Removed an item associated with the passed key fom the collection.
14715  * @param {String} key The key of the item to remove.
14716  */
14717     removeKey : function(key){
14718         return this.removeAt(this.indexOfKey(key));
14719     },
14720    
14721 /**
14722  * Returns the number of items in the collection.
14723  * @return {Number} the number of items in the collection.
14724  */
14725     getCount : function(){
14726         return this.length; 
14727     },
14728    
14729 /**
14730  * Returns index within the collection of the passed Object.
14731  * @param {Object} o The item to find the index of.
14732  * @return {Number} index of the item.
14733  */
14734     indexOf : function(o){
14735         if(!this.items.indexOf){
14736             for(var i = 0, len = this.items.length; i < len; i++){
14737                 if(this.items[i] == o) {
14738                     return i;
14739                 }
14740             }
14741             return -1;
14742         }else{
14743             return this.items.indexOf(o);
14744         }
14745     },
14746    
14747 /**
14748  * Returns index within the collection of the passed key.
14749  * @param {String} key The key to find the index of.
14750  * @return {Number} index of the key.
14751  */
14752     indexOfKey : function(key){
14753         if(!this.keys.indexOf){
14754             for(var i = 0, len = this.keys.length; i < len; i++){
14755                 if(this.keys[i] == key) {
14756                     return i;
14757                 }
14758             }
14759             return -1;
14760         }else{
14761             return this.keys.indexOf(key);
14762         }
14763     },
14764    
14765 /**
14766  * Returns the item associated with the passed key OR index. Key has priority over index.
14767  * @param {String/Number} key The key or index of the item.
14768  * @return {Object} The item associated with the passed key.
14769  */
14770     item : function(key){
14771         if (key === 'length') {
14772             return null;
14773         }
14774         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14775         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14776     },
14777     
14778 /**
14779  * Returns the item at the specified index.
14780  * @param {Number} index The index of the item.
14781  * @return {Object}
14782  */
14783     itemAt : function(index){
14784         return this.items[index];
14785     },
14786     
14787 /**
14788  * Returns the item associated with the passed key.
14789  * @param {String/Number} key The key of the item.
14790  * @return {Object} The item associated with the passed key.
14791  */
14792     key : function(key){
14793         return this.map[key];
14794     },
14795    
14796 /**
14797  * Returns true if the collection contains the passed Object as an item.
14798  * @param {Object} o  The Object to look for in the collection.
14799  * @return {Boolean} True if the collection contains the Object as an item.
14800  */
14801     contains : function(o){
14802         return this.indexOf(o) != -1;
14803     },
14804    
14805 /**
14806  * Returns true if the collection contains the passed Object as a key.
14807  * @param {String} key The key to look for in the collection.
14808  * @return {Boolean} True if the collection contains the Object as a key.
14809  */
14810     containsKey : function(key){
14811         return typeof this.map[key] != "undefined";
14812     },
14813    
14814 /**
14815  * Removes all items from the collection.
14816  */
14817     clear : function(){
14818         this.length = 0;
14819         this.items = [];
14820         this.keys = [];
14821         this.map = {};
14822         this.fireEvent("clear");
14823     },
14824    
14825 /**
14826  * Returns the first item in the collection.
14827  * @return {Object} the first item in the collection..
14828  */
14829     first : function(){
14830         return this.items[0]; 
14831     },
14832    
14833 /**
14834  * Returns the last item in the collection.
14835  * @return {Object} the last item in the collection..
14836  */
14837     last : function(){
14838         return this.items[this.length-1];   
14839     },
14840     
14841     _sort : function(property, dir, fn){
14842         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14843         fn = fn || function(a, b){
14844             return a-b;
14845         };
14846         var c = [], k = this.keys, items = this.items;
14847         for(var i = 0, len = items.length; i < len; i++){
14848             c[c.length] = {key: k[i], value: items[i], index: i};
14849         }
14850         c.sort(function(a, b){
14851             var v = fn(a[property], b[property]) * dsc;
14852             if(v == 0){
14853                 v = (a.index < b.index ? -1 : 1);
14854             }
14855             return v;
14856         });
14857         for(var i = 0, len = c.length; i < len; i++){
14858             items[i] = c[i].value;
14859             k[i] = c[i].key;
14860         }
14861         this.fireEvent("sort", this);
14862     },
14863     
14864     /**
14865      * Sorts this collection with the passed comparison function
14866      * @param {String} direction (optional) "ASC" or "DESC"
14867      * @param {Function} fn (optional) comparison function
14868      */
14869     sort : function(dir, fn){
14870         this._sort("value", dir, fn);
14871     },
14872     
14873     /**
14874      * Sorts this collection by keys
14875      * @param {String} direction (optional) "ASC" or "DESC"
14876      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14877      */
14878     keySort : function(dir, fn){
14879         this._sort("key", dir, fn || function(a, b){
14880             return String(a).toUpperCase()-String(b).toUpperCase();
14881         });
14882     },
14883     
14884     /**
14885      * Returns a range of items in this collection
14886      * @param {Number} startIndex (optional) defaults to 0
14887      * @param {Number} endIndex (optional) default to the last item
14888      * @return {Array} An array of items
14889      */
14890     getRange : function(start, end){
14891         var items = this.items;
14892         if(items.length < 1){
14893             return [];
14894         }
14895         start = start || 0;
14896         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14897         var r = [];
14898         if(start <= end){
14899             for(var i = start; i <= end; i++) {
14900                     r[r.length] = items[i];
14901             }
14902         }else{
14903             for(var i = start; i >= end; i--) {
14904                     r[r.length] = items[i];
14905             }
14906         }
14907         return r;
14908     },
14909         
14910     /**
14911      * Filter the <i>objects</i> in this collection by a specific property. 
14912      * Returns a new collection that has been filtered.
14913      * @param {String} property A property on your objects
14914      * @param {String/RegExp} value Either string that the property values 
14915      * should start with or a RegExp to test against the property
14916      * @return {MixedCollection} The new filtered collection
14917      */
14918     filter : function(property, value){
14919         if(!value.exec){ // not a regex
14920             value = String(value);
14921             if(value.length == 0){
14922                 return this.clone();
14923             }
14924             value = new RegExp("^" + Roo.escapeRe(value), "i");
14925         }
14926         return this.filterBy(function(o){
14927             return o && value.test(o[property]);
14928         });
14929         },
14930     
14931     /**
14932      * Filter by a function. * Returns a new collection that has been filtered.
14933      * The passed function will be called with each 
14934      * object in the collection. If the function returns true, the value is included 
14935      * otherwise it is filtered.
14936      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14937      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14938      * @return {MixedCollection} The new filtered collection
14939      */
14940     filterBy : function(fn, scope){
14941         var r = new Roo.util.MixedCollection();
14942         r.getKey = this.getKey;
14943         var k = this.keys, it = this.items;
14944         for(var i = 0, len = it.length; i < len; i++){
14945             if(fn.call(scope||this, it[i], k[i])){
14946                                 r.add(k[i], it[i]);
14947                         }
14948         }
14949         return r;
14950     },
14951     
14952     /**
14953      * Creates a duplicate of this collection
14954      * @return {MixedCollection}
14955      */
14956     clone : function(){
14957         var r = new Roo.util.MixedCollection();
14958         var k = this.keys, it = this.items;
14959         for(var i = 0, len = it.length; i < len; i++){
14960             r.add(k[i], it[i]);
14961         }
14962         r.getKey = this.getKey;
14963         return r;
14964     }
14965 });
14966 /**
14967  * Returns the item associated with the passed key or index.
14968  * @method
14969  * @param {String/Number} key The key or index of the item.
14970  * @return {Object} The item associated with the passed key.
14971  */
14972 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14973  * Based on:
14974  * Ext JS Library 1.1.1
14975  * Copyright(c) 2006-2007, Ext JS, LLC.
14976  *
14977  * Originally Released Under LGPL - original licence link has changed is not relivant.
14978  *
14979  * Fork - LGPL
14980  * <script type="text/javascript">
14981  */
14982 /**
14983  * @class Roo.util.JSON
14984  * Modified version of Douglas Crockford"s json.js that doesn"t
14985  * mess with the Object prototype 
14986  * http://www.json.org/js.html
14987  * @static
14988  */
14989 Roo.util.JSON = new (function(){
14990     var useHasOwn = {}.hasOwnProperty ? true : false;
14991     
14992     // crashes Safari in some instances
14993     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14994     
14995     var pad = function(n) {
14996         return n < 10 ? "0" + n : n;
14997     };
14998     
14999     var m = {
15000         "\b": '\\b',
15001         "\t": '\\t',
15002         "\n": '\\n',
15003         "\f": '\\f',
15004         "\r": '\\r',
15005         '"' : '\\"',
15006         "\\": '\\\\'
15007     };
15008
15009     var encodeString = function(s){
15010         if (/["\\\x00-\x1f]/.test(s)) {
15011             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15012                 var c = m[b];
15013                 if(c){
15014                     return c;
15015                 }
15016                 c = b.charCodeAt();
15017                 return "\\u00" +
15018                     Math.floor(c / 16).toString(16) +
15019                     (c % 16).toString(16);
15020             }) + '"';
15021         }
15022         return '"' + s + '"';
15023     };
15024     
15025     var encodeArray = function(o){
15026         var a = ["["], b, i, l = o.length, v;
15027             for (i = 0; i < l; i += 1) {
15028                 v = o[i];
15029                 switch (typeof v) {
15030                     case "undefined":
15031                     case "function":
15032                     case "unknown":
15033                         break;
15034                     default:
15035                         if (b) {
15036                             a.push(',');
15037                         }
15038                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15039                         b = true;
15040                 }
15041             }
15042             a.push("]");
15043             return a.join("");
15044     };
15045     
15046     var encodeDate = function(o){
15047         return '"' + o.getFullYear() + "-" +
15048                 pad(o.getMonth() + 1) + "-" +
15049                 pad(o.getDate()) + "T" +
15050                 pad(o.getHours()) + ":" +
15051                 pad(o.getMinutes()) + ":" +
15052                 pad(o.getSeconds()) + '"';
15053     };
15054     
15055     /**
15056      * Encodes an Object, Array or other value
15057      * @param {Mixed} o The variable to encode
15058      * @return {String} The JSON string
15059      */
15060     this.encode = function(o)
15061     {
15062         // should this be extended to fully wrap stringify..
15063         
15064         if(typeof o == "undefined" || o === null){
15065             return "null";
15066         }else if(o instanceof Array){
15067             return encodeArray(o);
15068         }else if(o instanceof Date){
15069             return encodeDate(o);
15070         }else if(typeof o == "string"){
15071             return encodeString(o);
15072         }else if(typeof o == "number"){
15073             return isFinite(o) ? String(o) : "null";
15074         }else if(typeof o == "boolean"){
15075             return String(o);
15076         }else {
15077             var a = ["{"], b, i, v;
15078             for (i in o) {
15079                 if(!useHasOwn || o.hasOwnProperty(i)) {
15080                     v = o[i];
15081                     switch (typeof v) {
15082                     case "undefined":
15083                     case "function":
15084                     case "unknown":
15085                         break;
15086                     default:
15087                         if(b){
15088                             a.push(',');
15089                         }
15090                         a.push(this.encode(i), ":",
15091                                 v === null ? "null" : this.encode(v));
15092                         b = true;
15093                     }
15094                 }
15095             }
15096             a.push("}");
15097             return a.join("");
15098         }
15099     };
15100     
15101     /**
15102      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15103      * @param {String} json The JSON string
15104      * @return {Object} The resulting object
15105      */
15106     this.decode = function(json){
15107         
15108         return  /** eval:var:json */ eval("(" + json + ')');
15109     };
15110 })();
15111 /** 
15112  * Shorthand for {@link Roo.util.JSON#encode}
15113  * @member Roo encode 
15114  * @method */
15115 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15116 /** 
15117  * Shorthand for {@link Roo.util.JSON#decode}
15118  * @member Roo decode 
15119  * @method */
15120 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15121 /*
15122  * Based on:
15123  * Ext JS Library 1.1.1
15124  * Copyright(c) 2006-2007, Ext JS, LLC.
15125  *
15126  * Originally Released Under LGPL - original licence link has changed is not relivant.
15127  *
15128  * Fork - LGPL
15129  * <script type="text/javascript">
15130  */
15131  
15132 /**
15133  * @class Roo.util.Format
15134  * Reusable data formatting functions
15135  * @static
15136  */
15137 Roo.util.Format = function(){
15138     var trimRe = /^\s+|\s+$/g;
15139     return {
15140         /**
15141          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15142          * @param {String} value The string to truncate
15143          * @param {Number} length The maximum length to allow before truncating
15144          * @return {String} The converted text
15145          */
15146         ellipsis : function(value, len){
15147             if(value && value.length > len){
15148                 return value.substr(0, len-3)+"...";
15149             }
15150             return value;
15151         },
15152
15153         /**
15154          * Checks a reference and converts it to empty string if it is undefined
15155          * @param {Mixed} value Reference to check
15156          * @return {Mixed} Empty string if converted, otherwise the original value
15157          */
15158         undef : function(value){
15159             return typeof value != "undefined" ? value : "";
15160         },
15161
15162         /**
15163          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15164          * @param {String} value The string to encode
15165          * @return {String} The encoded text
15166          */
15167         htmlEncode : function(value){
15168             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
15169         },
15170
15171         /**
15172          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15173          * @param {String} value The string to decode
15174          * @return {String} The decoded text
15175          */
15176         htmlDecode : function(value){
15177             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15178         },
15179
15180         /**
15181          * Trims any whitespace from either side of a string
15182          * @param {String} value The text to trim
15183          * @return {String} The trimmed text
15184          */
15185         trim : function(value){
15186             return String(value).replace(trimRe, "");
15187         },
15188
15189         /**
15190          * Returns a substring from within an original string
15191          * @param {String} value The original text
15192          * @param {Number} start The start index of the substring
15193          * @param {Number} length The length of the substring
15194          * @return {String} The substring
15195          */
15196         substr : function(value, start, length){
15197             return String(value).substr(start, length);
15198         },
15199
15200         /**
15201          * Converts a string to all lower case letters
15202          * @param {String} value The text to convert
15203          * @return {String} The converted text
15204          */
15205         lowercase : function(value){
15206             return String(value).toLowerCase();
15207         },
15208
15209         /**
15210          * Converts a string to all upper case letters
15211          * @param {String} value The text to convert
15212          * @return {String} The converted text
15213          */
15214         uppercase : function(value){
15215             return String(value).toUpperCase();
15216         },
15217
15218         /**
15219          * Converts the first character only of a string to upper case
15220          * @param {String} value The text to convert
15221          * @return {String} The converted text
15222          */
15223         capitalize : function(value){
15224             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15225         },
15226
15227         // private
15228         call : function(value, fn){
15229             if(arguments.length > 2){
15230                 var args = Array.prototype.slice.call(arguments, 2);
15231                 args.unshift(value);
15232                  
15233                 return /** eval:var:value */  eval(fn).apply(window, args);
15234             }else{
15235                 /** eval:var:value */
15236                 return /** eval:var:value */ eval(fn).call(window, value);
15237             }
15238         },
15239
15240        
15241         /**
15242          * safer version of Math.toFixed..??/
15243          * @param {Number/String} value The numeric value to format
15244          * @param {Number/String} value Decimal places 
15245          * @return {String} The formatted currency string
15246          */
15247         toFixed : function(v, n)
15248         {
15249             // why not use to fixed - precision is buggered???
15250             if (!n) {
15251                 return Math.round(v-0);
15252             }
15253             var fact = Math.pow(10,n+1);
15254             v = (Math.round((v-0)*fact))/fact;
15255             var z = (''+fact).substring(2);
15256             if (v == Math.floor(v)) {
15257                 return Math.floor(v) + '.' + z;
15258             }
15259             
15260             // now just padd decimals..
15261             var ps = String(v).split('.');
15262             var fd = (ps[1] + z);
15263             var r = fd.substring(0,n); 
15264             var rm = fd.substring(n); 
15265             if (rm < 5) {
15266                 return ps[0] + '.' + r;
15267             }
15268             r*=1; // turn it into a number;
15269             r++;
15270             if (String(r).length != n) {
15271                 ps[0]*=1;
15272                 ps[0]++;
15273                 r = String(r).substring(1); // chop the end off.
15274             }
15275             
15276             return ps[0] + '.' + r;
15277              
15278         },
15279         
15280         /**
15281          * Format a number as US currency
15282          * @param {Number/String} value The numeric value to format
15283          * @return {String} The formatted currency string
15284          */
15285         usMoney : function(v){
15286             return '$' + Roo.util.Format.number(v);
15287         },
15288         
15289         /**
15290          * Format a number
15291          * eventually this should probably emulate php's number_format
15292          * @param {Number/String} value The numeric value to format
15293          * @param {Number} decimals number of decimal places
15294          * @param {String} delimiter for thousands (default comma)
15295          * @return {String} The formatted currency string
15296          */
15297         number : function(v, decimals, thousandsDelimiter)
15298         {
15299             // multiply and round.
15300             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15301             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15302             
15303             var mul = Math.pow(10, decimals);
15304             var zero = String(mul).substring(1);
15305             v = (Math.round((v-0)*mul))/mul;
15306             
15307             // if it's '0' number.. then
15308             
15309             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15310             v = String(v);
15311             var ps = v.split('.');
15312             var whole = ps[0];
15313             
15314             var r = /(\d+)(\d{3})/;
15315             // add comma's
15316             
15317             if(thousandsDelimiter.length != 0) {
15318                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15319             } 
15320             
15321             var sub = ps[1] ?
15322                     // has decimals..
15323                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15324                     // does not have decimals
15325                     (decimals ? ('.' + zero) : '');
15326             
15327             
15328             return whole + sub ;
15329         },
15330         
15331         /**
15332          * Parse a value into a formatted date using the specified format pattern.
15333          * @param {Mixed} value The value to format
15334          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15335          * @return {String} The formatted date string
15336          */
15337         date : function(v, format){
15338             if(!v){
15339                 return "";
15340             }
15341             if(!(v instanceof Date)){
15342                 v = new Date(Date.parse(v));
15343             }
15344             return v.dateFormat(format || Roo.util.Format.defaults.date);
15345         },
15346
15347         /**
15348          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15349          * @param {String} format Any valid date format string
15350          * @return {Function} The date formatting function
15351          */
15352         dateRenderer : function(format){
15353             return function(v){
15354                 return Roo.util.Format.date(v, format);  
15355             };
15356         },
15357
15358         // private
15359         stripTagsRE : /<\/?[^>]+>/gi,
15360         
15361         /**
15362          * Strips all HTML tags
15363          * @param {Mixed} value The text from which to strip tags
15364          * @return {String} The stripped text
15365          */
15366         stripTags : function(v){
15367             return !v ? v : String(v).replace(this.stripTagsRE, "");
15368         },
15369         
15370         /**
15371          * Size in Mb,Gb etc.
15372          * @param {Number} value The number to be formated
15373          * @param {number} decimals how many decimal places
15374          * @return {String} the formated string
15375          */
15376         size : function(value, decimals)
15377         {
15378             var sizes = ['b', 'k', 'M', 'G', 'T'];
15379             if (value == 0) {
15380                 return 0;
15381             }
15382             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15383             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15384         }
15385         
15386         
15387         
15388     };
15389 }();
15390 Roo.util.Format.defaults = {
15391     date : 'd/M/Y'
15392 };/*
15393  * Based on:
15394  * Ext JS Library 1.1.1
15395  * Copyright(c) 2006-2007, Ext JS, LLC.
15396  *
15397  * Originally Released Under LGPL - original licence link has changed is not relivant.
15398  *
15399  * Fork - LGPL
15400  * <script type="text/javascript">
15401  */
15402
15403
15404  
15405
15406 /**
15407  * @class Roo.MasterTemplate
15408  * @extends Roo.Template
15409  * Provides a template that can have child templates. The syntax is:
15410 <pre><code>
15411 var t = new Roo.MasterTemplate(
15412         '&lt;select name="{name}"&gt;',
15413                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15414         '&lt;/select&gt;'
15415 );
15416 t.add('options', {value: 'foo', text: 'bar'});
15417 // or you can add multiple child elements in one shot
15418 t.addAll('options', [
15419     {value: 'foo', text: 'bar'},
15420     {value: 'foo2', text: 'bar2'},
15421     {value: 'foo3', text: 'bar3'}
15422 ]);
15423 // then append, applying the master template values
15424 t.append('my-form', {name: 'my-select'});
15425 </code></pre>
15426 * A name attribute for the child template is not required if you have only one child
15427 * template or you want to refer to them by index.
15428  */
15429 Roo.MasterTemplate = function(){
15430     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15431     this.originalHtml = this.html;
15432     var st = {};
15433     var m, re = this.subTemplateRe;
15434     re.lastIndex = 0;
15435     var subIndex = 0;
15436     while(m = re.exec(this.html)){
15437         var name = m[1], content = m[2];
15438         st[subIndex] = {
15439             name: name,
15440             index: subIndex,
15441             buffer: [],
15442             tpl : new Roo.Template(content)
15443         };
15444         if(name){
15445             st[name] = st[subIndex];
15446         }
15447         st[subIndex].tpl.compile();
15448         st[subIndex].tpl.call = this.call.createDelegate(this);
15449         subIndex++;
15450     }
15451     this.subCount = subIndex;
15452     this.subs = st;
15453 };
15454 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15455     /**
15456     * The regular expression used to match sub templates
15457     * @type RegExp
15458     * @property
15459     */
15460     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15461
15462     /**
15463      * Applies the passed values to a child template.
15464      * @param {String/Number} name (optional) The name or index of the child template
15465      * @param {Array/Object} values The values to be applied to the template
15466      * @return {MasterTemplate} this
15467      */
15468      add : function(name, values){
15469         if(arguments.length == 1){
15470             values = arguments[0];
15471             name = 0;
15472         }
15473         var s = this.subs[name];
15474         s.buffer[s.buffer.length] = s.tpl.apply(values);
15475         return this;
15476     },
15477
15478     /**
15479      * Applies all the passed values to a child template.
15480      * @param {String/Number} name (optional) The name or index of the child template
15481      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15482      * @param {Boolean} reset (optional) True to reset the template first
15483      * @return {MasterTemplate} this
15484      */
15485     fill : function(name, values, reset){
15486         var a = arguments;
15487         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15488             values = a[0];
15489             name = 0;
15490             reset = a[1];
15491         }
15492         if(reset){
15493             this.reset();
15494         }
15495         for(var i = 0, len = values.length; i < len; i++){
15496             this.add(name, values[i]);
15497         }
15498         return this;
15499     },
15500
15501     /**
15502      * Resets the template for reuse
15503      * @return {MasterTemplate} this
15504      */
15505      reset : function(){
15506         var s = this.subs;
15507         for(var i = 0; i < this.subCount; i++){
15508             s[i].buffer = [];
15509         }
15510         return this;
15511     },
15512
15513     applyTemplate : function(values){
15514         var s = this.subs;
15515         var replaceIndex = -1;
15516         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15517             return s[++replaceIndex].buffer.join("");
15518         });
15519         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15520     },
15521
15522     apply : function(){
15523         return this.applyTemplate.apply(this, arguments);
15524     },
15525
15526     compile : function(){return this;}
15527 });
15528
15529 /**
15530  * Alias for fill().
15531  * @method
15532  */
15533 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15534  /**
15535  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15536  * var tpl = Roo.MasterTemplate.from('element-id');
15537  * @param {String/HTMLElement} el
15538  * @param {Object} config
15539  * @static
15540  */
15541 Roo.MasterTemplate.from = function(el, config){
15542     el = Roo.getDom(el);
15543     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15544 };/*
15545  * Based on:
15546  * Ext JS Library 1.1.1
15547  * Copyright(c) 2006-2007, Ext JS, LLC.
15548  *
15549  * Originally Released Under LGPL - original licence link has changed is not relivant.
15550  *
15551  * Fork - LGPL
15552  * <script type="text/javascript">
15553  */
15554
15555  
15556 /**
15557  * @class Roo.util.CSS
15558  * Utility class for manipulating CSS rules
15559  * @static
15560
15561  */
15562 Roo.util.CSS = function(){
15563         var rules = null;
15564         var doc = document;
15565
15566     var camelRe = /(-[a-z])/gi;
15567     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15568
15569    return {
15570    /**
15571     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15572     * tag and appended to the HEAD of the document.
15573     * @param {String|Object} cssText The text containing the css rules
15574     * @param {String} id An id to add to the stylesheet for later removal
15575     * @return {StyleSheet}
15576     */
15577     createStyleSheet : function(cssText, id){
15578         var ss;
15579         var head = doc.getElementsByTagName("head")[0];
15580         var nrules = doc.createElement("style");
15581         nrules.setAttribute("type", "text/css");
15582         if(id){
15583             nrules.setAttribute("id", id);
15584         }
15585         if (typeof(cssText) != 'string') {
15586             // support object maps..
15587             // not sure if this a good idea.. 
15588             // perhaps it should be merged with the general css handling
15589             // and handle js style props.
15590             var cssTextNew = [];
15591             for(var n in cssText) {
15592                 var citems = [];
15593                 for(var k in cssText[n]) {
15594                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15595                 }
15596                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15597                 
15598             }
15599             cssText = cssTextNew.join("\n");
15600             
15601         }
15602        
15603        
15604        if(Roo.isIE){
15605            head.appendChild(nrules);
15606            ss = nrules.styleSheet;
15607            ss.cssText = cssText;
15608        }else{
15609            try{
15610                 nrules.appendChild(doc.createTextNode(cssText));
15611            }catch(e){
15612                nrules.cssText = cssText; 
15613            }
15614            head.appendChild(nrules);
15615            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15616        }
15617        this.cacheStyleSheet(ss);
15618        return ss;
15619    },
15620
15621    /**
15622     * Removes a style or link tag by id
15623     * @param {String} id The id of the tag
15624     */
15625    removeStyleSheet : function(id){
15626        var existing = doc.getElementById(id);
15627        if(existing){
15628            existing.parentNode.removeChild(existing);
15629        }
15630    },
15631
15632    /**
15633     * Dynamically swaps an existing stylesheet reference for a new one
15634     * @param {String} id The id of an existing link tag to remove
15635     * @param {String} url The href of the new stylesheet to include
15636     */
15637    swapStyleSheet : function(id, url){
15638        this.removeStyleSheet(id);
15639        var ss = doc.createElement("link");
15640        ss.setAttribute("rel", "stylesheet");
15641        ss.setAttribute("type", "text/css");
15642        ss.setAttribute("id", id);
15643        ss.setAttribute("href", url);
15644        doc.getElementsByTagName("head")[0].appendChild(ss);
15645    },
15646    
15647    /**
15648     * Refresh the rule cache if you have dynamically added stylesheets
15649     * @return {Object} An object (hash) of rules indexed by selector
15650     */
15651    refreshCache : function(){
15652        return this.getRules(true);
15653    },
15654
15655    // private
15656    cacheStyleSheet : function(stylesheet){
15657        if(!rules){
15658            rules = {};
15659        }
15660        try{// try catch for cross domain access issue
15661            var ssRules = stylesheet.cssRules || stylesheet.rules;
15662            for(var j = ssRules.length-1; j >= 0; --j){
15663                rules[ssRules[j].selectorText] = ssRules[j];
15664            }
15665        }catch(e){}
15666    },
15667    
15668    /**
15669     * Gets all css rules for the document
15670     * @param {Boolean} refreshCache true to refresh the internal cache
15671     * @return {Object} An object (hash) of rules indexed by selector
15672     */
15673    getRules : function(refreshCache){
15674                 if(rules == null || refreshCache){
15675                         rules = {};
15676                         var ds = doc.styleSheets;
15677                         for(var i =0, len = ds.length; i < len; i++){
15678                             try{
15679                         this.cacheStyleSheet(ds[i]);
15680                     }catch(e){} 
15681                 }
15682                 }
15683                 return rules;
15684         },
15685         
15686         /**
15687     * Gets an an individual CSS rule by selector(s)
15688     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15689     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15690     * @return {CSSRule} The CSS rule or null if one is not found
15691     */
15692    getRule : function(selector, refreshCache){
15693                 var rs = this.getRules(refreshCache);
15694                 if(!(selector instanceof Array)){
15695                     return rs[selector];
15696                 }
15697                 for(var i = 0; i < selector.length; i++){
15698                         if(rs[selector[i]]){
15699                                 return rs[selector[i]];
15700                         }
15701                 }
15702                 return null;
15703         },
15704         
15705         
15706         /**
15707     * Updates a rule property
15708     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15709     * @param {String} property The css property
15710     * @param {String} value The new value for the property
15711     * @return {Boolean} true If a rule was found and updated
15712     */
15713    updateRule : function(selector, property, value){
15714                 if(!(selector instanceof Array)){
15715                         var rule = this.getRule(selector);
15716                         if(rule){
15717                                 rule.style[property.replace(camelRe, camelFn)] = value;
15718                                 return true;
15719                         }
15720                 }else{
15721                         for(var i = 0; i < selector.length; i++){
15722                                 if(this.updateRule(selector[i], property, value)){
15723                                         return true;
15724                                 }
15725                         }
15726                 }
15727                 return false;
15728         }
15729    };   
15730 }();/*
15731  * Based on:
15732  * Ext JS Library 1.1.1
15733  * Copyright(c) 2006-2007, Ext JS, LLC.
15734  *
15735  * Originally Released Under LGPL - original licence link has changed is not relivant.
15736  *
15737  * Fork - LGPL
15738  * <script type="text/javascript">
15739  */
15740
15741  
15742
15743 /**
15744  * @class Roo.util.ClickRepeater
15745  * @extends Roo.util.Observable
15746  * 
15747  * A wrapper class which can be applied to any element. Fires a "click" event while the
15748  * mouse is pressed. The interval between firings may be specified in the config but
15749  * defaults to 10 milliseconds.
15750  * 
15751  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15752  * 
15753  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15754  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15755  * Similar to an autorepeat key delay.
15756  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15757  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15758  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15759  *           "interval" and "delay" are ignored. "immediate" is honored.
15760  * @cfg {Boolean} preventDefault True to prevent the default click event
15761  * @cfg {Boolean} stopDefault True to stop the default click event
15762  * 
15763  * @history
15764  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15765  *     2007-02-02 jvs Renamed to ClickRepeater
15766  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15767  *
15768  *  @constructor
15769  * @param {String/HTMLElement/Element} el The element to listen on
15770  * @param {Object} config
15771  **/
15772 Roo.util.ClickRepeater = function(el, config)
15773 {
15774     this.el = Roo.get(el);
15775     this.el.unselectable();
15776
15777     Roo.apply(this, config);
15778
15779     this.addEvents({
15780     /**
15781      * @event mousedown
15782      * Fires when the mouse button is depressed.
15783      * @param {Roo.util.ClickRepeater} this
15784      */
15785         "mousedown" : true,
15786     /**
15787      * @event click
15788      * Fires on a specified interval during the time the element is pressed.
15789      * @param {Roo.util.ClickRepeater} this
15790      */
15791         "click" : true,
15792     /**
15793      * @event mouseup
15794      * Fires when the mouse key is released.
15795      * @param {Roo.util.ClickRepeater} this
15796      */
15797         "mouseup" : true
15798     });
15799
15800     this.el.on("mousedown", this.handleMouseDown, this);
15801     if(this.preventDefault || this.stopDefault){
15802         this.el.on("click", function(e){
15803             if(this.preventDefault){
15804                 e.preventDefault();
15805             }
15806             if(this.stopDefault){
15807                 e.stopEvent();
15808             }
15809         }, this);
15810     }
15811
15812     // allow inline handler
15813     if(this.handler){
15814         this.on("click", this.handler,  this.scope || this);
15815     }
15816
15817     Roo.util.ClickRepeater.superclass.constructor.call(this);
15818 };
15819
15820 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15821     interval : 20,
15822     delay: 250,
15823     preventDefault : true,
15824     stopDefault : false,
15825     timer : 0,
15826
15827     // private
15828     handleMouseDown : function(){
15829         clearTimeout(this.timer);
15830         this.el.blur();
15831         if(this.pressClass){
15832             this.el.addClass(this.pressClass);
15833         }
15834         this.mousedownTime = new Date();
15835
15836         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15837         this.el.on("mouseout", this.handleMouseOut, this);
15838
15839         this.fireEvent("mousedown", this);
15840         this.fireEvent("click", this);
15841         
15842         this.timer = this.click.defer(this.delay || this.interval, this);
15843     },
15844
15845     // private
15846     click : function(){
15847         this.fireEvent("click", this);
15848         this.timer = this.click.defer(this.getInterval(), this);
15849     },
15850
15851     // private
15852     getInterval: function(){
15853         if(!this.accelerate){
15854             return this.interval;
15855         }
15856         var pressTime = this.mousedownTime.getElapsed();
15857         if(pressTime < 500){
15858             return 400;
15859         }else if(pressTime < 1700){
15860             return 320;
15861         }else if(pressTime < 2600){
15862             return 250;
15863         }else if(pressTime < 3500){
15864             return 180;
15865         }else if(pressTime < 4400){
15866             return 140;
15867         }else if(pressTime < 5300){
15868             return 80;
15869         }else if(pressTime < 6200){
15870             return 50;
15871         }else{
15872             return 10;
15873         }
15874     },
15875
15876     // private
15877     handleMouseOut : function(){
15878         clearTimeout(this.timer);
15879         if(this.pressClass){
15880             this.el.removeClass(this.pressClass);
15881         }
15882         this.el.on("mouseover", this.handleMouseReturn, this);
15883     },
15884
15885     // private
15886     handleMouseReturn : function(){
15887         this.el.un("mouseover", this.handleMouseReturn);
15888         if(this.pressClass){
15889             this.el.addClass(this.pressClass);
15890         }
15891         this.click();
15892     },
15893
15894     // private
15895     handleMouseUp : function(){
15896         clearTimeout(this.timer);
15897         this.el.un("mouseover", this.handleMouseReturn);
15898         this.el.un("mouseout", this.handleMouseOut);
15899         Roo.get(document).un("mouseup", this.handleMouseUp);
15900         this.el.removeClass(this.pressClass);
15901         this.fireEvent("mouseup", this);
15902     }
15903 });/**
15904  * @class Roo.util.Clipboard
15905  * @static
15906  * 
15907  * Clipboard UTILS
15908  * 
15909  **/
15910 Roo.util.Clipboard = {
15911     /**
15912      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15913      * @param {String} text to copy to clipboard
15914      */
15915     write : function(text) {
15916         // navigator clipboard api needs a secure context (https)
15917         if (navigator.clipboard && window.isSecureContext) {
15918             // navigator clipboard api method'
15919             navigator.clipboard.writeText(text);
15920             return ;
15921         } 
15922         // text area method
15923         var ta = document.createElement("textarea");
15924         ta.value = text;
15925         // make the textarea out of viewport
15926         ta.style.position = "fixed";
15927         ta.style.left = "-999999px";
15928         ta.style.top = "-999999px";
15929         document.body.appendChild(ta);
15930         ta.focus();
15931         ta.select();
15932         document.execCommand('copy');
15933         (function() {
15934             ta.remove();
15935         }).defer(100);
15936         
15937     }
15938         
15939 }
15940     /*
15941  * Based on:
15942  * Ext JS Library 1.1.1
15943  * Copyright(c) 2006-2007, Ext JS, LLC.
15944  *
15945  * Originally Released Under LGPL - original licence link has changed is not relivant.
15946  *
15947  * Fork - LGPL
15948  * <script type="text/javascript">
15949  */
15950
15951  
15952 /**
15953  * @class Roo.KeyNav
15954  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15955  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15956  * way to implement custom navigation schemes for any UI component.</p>
15957  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15958  * pageUp, pageDown, del, home, end.  Usage:</p>
15959  <pre><code>
15960 var nav = new Roo.KeyNav("my-element", {
15961     "left" : function(e){
15962         this.moveLeft(e.ctrlKey);
15963     },
15964     "right" : function(e){
15965         this.moveRight(e.ctrlKey);
15966     },
15967     "enter" : function(e){
15968         this.save();
15969     },
15970     scope : this
15971 });
15972 </code></pre>
15973  * @constructor
15974  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15975  * @param {Object} config The config
15976  */
15977 Roo.KeyNav = function(el, config){
15978     this.el = Roo.get(el);
15979     Roo.apply(this, config);
15980     if(!this.disabled){
15981         this.disabled = true;
15982         this.enable();
15983     }
15984 };
15985
15986 Roo.KeyNav.prototype = {
15987     /**
15988      * @cfg {Boolean} disabled
15989      * True to disable this KeyNav instance (defaults to false)
15990      */
15991     disabled : false,
15992     /**
15993      * @cfg {String} defaultEventAction
15994      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15995      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15996      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15997      */
15998     defaultEventAction: "stopEvent",
15999     /**
16000      * @cfg {Boolean} forceKeyDown
16001      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
16002      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16003      * handle keydown instead of keypress.
16004      */
16005     forceKeyDown : false,
16006
16007     // private
16008     prepareEvent : function(e){
16009         var k = e.getKey();
16010         var h = this.keyToHandler[k];
16011         //if(h && this[h]){
16012         //    e.stopPropagation();
16013         //}
16014         if(Roo.isSafari && h && k >= 37 && k <= 40){
16015             e.stopEvent();
16016         }
16017     },
16018
16019     // private
16020     relay : function(e){
16021         var k = e.getKey();
16022         var h = this.keyToHandler[k];
16023         if(h && this[h]){
16024             if(this.doRelay(e, this[h], h) !== true){
16025                 e[this.defaultEventAction]();
16026             }
16027         }
16028     },
16029
16030     // private
16031     doRelay : function(e, h, hname){
16032         return h.call(this.scope || this, e);
16033     },
16034
16035     // possible handlers
16036     enter : false,
16037     left : false,
16038     right : false,
16039     up : false,
16040     down : false,
16041     tab : false,
16042     esc : false,
16043     pageUp : false,
16044     pageDown : false,
16045     del : false,
16046     home : false,
16047     end : false,
16048
16049     // quick lookup hash
16050     keyToHandler : {
16051         37 : "left",
16052         39 : "right",
16053         38 : "up",
16054         40 : "down",
16055         33 : "pageUp",
16056         34 : "pageDown",
16057         46 : "del",
16058         36 : "home",
16059         35 : "end",
16060         13 : "enter",
16061         27 : "esc",
16062         9  : "tab"
16063     },
16064
16065         /**
16066          * Enable this KeyNav
16067          */
16068         enable: function(){
16069                 if(this.disabled){
16070             // ie won't do special keys on keypress, no one else will repeat keys with keydown
16071             // the EventObject will normalize Safari automatically
16072             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16073                 this.el.on("keydown", this.relay,  this);
16074             }else{
16075                 this.el.on("keydown", this.prepareEvent,  this);
16076                 this.el.on("keypress", this.relay,  this);
16077             }
16078                     this.disabled = false;
16079                 }
16080         },
16081
16082         /**
16083          * Disable this KeyNav
16084          */
16085         disable: function(){
16086                 if(!this.disabled){
16087                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16088                 this.el.un("keydown", this.relay);
16089             }else{
16090                 this.el.un("keydown", this.prepareEvent);
16091                 this.el.un("keypress", this.relay);
16092             }
16093                     this.disabled = true;
16094                 }
16095         }
16096 };/*
16097  * Based on:
16098  * Ext JS Library 1.1.1
16099  * Copyright(c) 2006-2007, Ext JS, LLC.
16100  *
16101  * Originally Released Under LGPL - original licence link has changed is not relivant.
16102  *
16103  * Fork - LGPL
16104  * <script type="text/javascript">
16105  */
16106
16107  
16108 /**
16109  * @class Roo.KeyMap
16110  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16111  * The constructor accepts the same config object as defined by {@link #addBinding}.
16112  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16113  * combination it will call the function with this signature (if the match is a multi-key
16114  * combination the callback will still be called only once): (String key, Roo.EventObject e)
16115  * A KeyMap can also handle a string representation of keys.<br />
16116  * Usage:
16117  <pre><code>
16118 // map one key by key code
16119 var map = new Roo.KeyMap("my-element", {
16120     key: 13, // or Roo.EventObject.ENTER
16121     fn: myHandler,
16122     scope: myObject
16123 });
16124
16125 // map multiple keys to one action by string
16126 var map = new Roo.KeyMap("my-element", {
16127     key: "a\r\n\t",
16128     fn: myHandler,
16129     scope: myObject
16130 });
16131
16132 // map multiple keys to multiple actions by strings and array of codes
16133 var map = new Roo.KeyMap("my-element", [
16134     {
16135         key: [10,13],
16136         fn: function(){ alert("Return was pressed"); }
16137     }, {
16138         key: "abc",
16139         fn: function(){ alert('a, b or c was pressed'); }
16140     }, {
16141         key: "\t",
16142         ctrl:true,
16143         shift:true,
16144         fn: function(){ alert('Control + shift + tab was pressed.'); }
16145     }
16146 ]);
16147 </code></pre>
16148  * <b>Note: A KeyMap starts enabled</b>
16149  * @constructor
16150  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16151  * @param {Object} config The config (see {@link #addBinding})
16152  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16153  */
16154 Roo.KeyMap = function(el, config, eventName){
16155     this.el  = Roo.get(el);
16156     this.eventName = eventName || "keydown";
16157     this.bindings = [];
16158     if(config){
16159         this.addBinding(config);
16160     }
16161     this.enable();
16162 };
16163
16164 Roo.KeyMap.prototype = {
16165     /**
16166      * True to stop the event from bubbling and prevent the default browser action if the
16167      * key was handled by the KeyMap (defaults to false)
16168      * @type Boolean
16169      */
16170     stopEvent : false,
16171
16172     /**
16173      * Add a new binding to this KeyMap. The following config object properties are supported:
16174      * <pre>
16175 Property    Type             Description
16176 ----------  ---------------  ----------------------------------------------------------------------
16177 key         String/Array     A single keycode or an array of keycodes to handle
16178 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16179 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16180 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16181 fn          Function         The function to call when KeyMap finds the expected key combination
16182 scope       Object           The scope of the callback function
16183 </pre>
16184      *
16185      * Usage:
16186      * <pre><code>
16187 // Create a KeyMap
16188 var map = new Roo.KeyMap(document, {
16189     key: Roo.EventObject.ENTER,
16190     fn: handleKey,
16191     scope: this
16192 });
16193
16194 //Add a new binding to the existing KeyMap later
16195 map.addBinding({
16196     key: 'abc',
16197     shift: true,
16198     fn: handleKey,
16199     scope: this
16200 });
16201 </code></pre>
16202      * @param {Object/Array} config A single KeyMap config or an array of configs
16203      */
16204         addBinding : function(config){
16205         if(config instanceof Array){
16206             for(var i = 0, len = config.length; i < len; i++){
16207                 this.addBinding(config[i]);
16208             }
16209             return;
16210         }
16211         var keyCode = config.key,
16212             shift = config.shift, 
16213             ctrl = config.ctrl, 
16214             alt = config.alt,
16215             fn = config.fn,
16216             scope = config.scope;
16217         if(typeof keyCode == "string"){
16218             var ks = [];
16219             var keyString = keyCode.toUpperCase();
16220             for(var j = 0, len = keyString.length; j < len; j++){
16221                 ks.push(keyString.charCodeAt(j));
16222             }
16223             keyCode = ks;
16224         }
16225         var keyArray = keyCode instanceof Array;
16226         var handler = function(e){
16227             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16228                 var k = e.getKey();
16229                 if(keyArray){
16230                     for(var i = 0, len = keyCode.length; i < len; i++){
16231                         if(keyCode[i] == k){
16232                           if(this.stopEvent){
16233                               e.stopEvent();
16234                           }
16235                           fn.call(scope || window, k, e);
16236                           return;
16237                         }
16238                     }
16239                 }else{
16240                     if(k == keyCode){
16241                         if(this.stopEvent){
16242                            e.stopEvent();
16243                         }
16244                         fn.call(scope || window, k, e);
16245                     }
16246                 }
16247             }
16248         };
16249         this.bindings.push(handler);  
16250         },
16251
16252     /**
16253      * Shorthand for adding a single key listener
16254      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16255      * following options:
16256      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16257      * @param {Function} fn The function to call
16258      * @param {Object} scope (optional) The scope of the function
16259      */
16260     on : function(key, fn, scope){
16261         var keyCode, shift, ctrl, alt;
16262         if(typeof key == "object" && !(key instanceof Array)){
16263             keyCode = key.key;
16264             shift = key.shift;
16265             ctrl = key.ctrl;
16266             alt = key.alt;
16267         }else{
16268             keyCode = key;
16269         }
16270         this.addBinding({
16271             key: keyCode,
16272             shift: shift,
16273             ctrl: ctrl,
16274             alt: alt,
16275             fn: fn,
16276             scope: scope
16277         })
16278     },
16279
16280     // private
16281     handleKeyDown : function(e){
16282             if(this.enabled){ //just in case
16283             var b = this.bindings;
16284             for(var i = 0, len = b.length; i < len; i++){
16285                 b[i].call(this, e);
16286             }
16287             }
16288         },
16289         
16290         /**
16291          * Returns true if this KeyMap is enabled
16292          * @return {Boolean} 
16293          */
16294         isEnabled : function(){
16295             return this.enabled;  
16296         },
16297         
16298         /**
16299          * Enables this KeyMap
16300          */
16301         enable: function(){
16302                 if(!this.enabled){
16303                     this.el.on(this.eventName, this.handleKeyDown, this);
16304                     this.enabled = true;
16305                 }
16306         },
16307
16308         /**
16309          * Disable this KeyMap
16310          */
16311         disable: function(){
16312                 if(this.enabled){
16313                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16314                     this.enabled = false;
16315                 }
16316         }
16317 };/*
16318  * Based on:
16319  * Ext JS Library 1.1.1
16320  * Copyright(c) 2006-2007, Ext JS, LLC.
16321  *
16322  * Originally Released Under LGPL - original licence link has changed is not relivant.
16323  *
16324  * Fork - LGPL
16325  * <script type="text/javascript">
16326  */
16327
16328  
16329 /**
16330  * @class Roo.util.TextMetrics
16331  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16332  * wide, in pixels, a given block of text will be.
16333  * @static
16334  */
16335 Roo.util.TextMetrics = function(){
16336     var shared;
16337     return {
16338         /**
16339          * Measures the size of the specified text
16340          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16341          * that can affect the size of the rendered text
16342          * @param {String} text The text to measure
16343          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16344          * in order to accurately measure the text height
16345          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16346          */
16347         measure : function(el, text, fixedWidth){
16348             if(!shared){
16349                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16350             }
16351             shared.bind(el);
16352             shared.setFixedWidth(fixedWidth || 'auto');
16353             return shared.getSize(text);
16354         },
16355
16356         /**
16357          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16358          * the overhead of multiple calls to initialize the style properties on each measurement.
16359          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16360          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16361          * in order to accurately measure the text height
16362          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16363          */
16364         createInstance : function(el, fixedWidth){
16365             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16366         }
16367     };
16368 }();
16369
16370 /**
16371  * @class Roo.util.TextMetrics.Instance
16372  * Instance of  TextMetrics Calcuation
16373  * @constructor
16374  * Create a new TextMetrics Instance
16375  * @param {Object} bindto
16376  * @param {Boolean} fixedWidth
16377  */
16378
16379 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16380 {
16381     var ml = new Roo.Element(document.createElement('div'));
16382     document.body.appendChild(ml.dom);
16383     ml.position('absolute');
16384     ml.setLeftTop(-1000, -1000);
16385     ml.hide();
16386
16387     if(fixedWidth){
16388         ml.setWidth(fixedWidth);
16389     }
16390      
16391     var instance = {
16392         /**
16393          * Returns the size of the specified text based on the internal element's style and width properties
16394          * @param {String} text The text to measure
16395          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16396          */
16397         getSize : function(text){
16398             ml.update(text);
16399             var s = ml.getSize();
16400             ml.update('');
16401             return s;
16402         },
16403
16404         /**
16405          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16406          * that can affect the size of the rendered text
16407          * @param {String/HTMLElement} el The element, dom node or id
16408          */
16409         bind : function(el){
16410             ml.setStyle(
16411                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16412             );
16413         },
16414
16415         /**
16416          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16417          * to set a fixed width in order to accurately measure the text height.
16418          * @param {Number} width The width to set on the element
16419          */
16420         setFixedWidth : function(width){
16421             ml.setWidth(width);
16422         },
16423
16424         /**
16425          * Returns the measured width of the specified text
16426          * @param {String} text The text to measure
16427          * @return {Number} width The width in pixels
16428          */
16429         getWidth : function(text){
16430             ml.dom.style.width = 'auto';
16431             return this.getSize(text).width;
16432         },
16433
16434         /**
16435          * Returns the measured height of the specified text.  For multiline text, be sure to call
16436          * {@link #setFixedWidth} if necessary.
16437          * @param {String} text The text to measure
16438          * @return {Number} height The height in pixels
16439          */
16440         getHeight : function(text){
16441             return this.getSize(text).height;
16442         }
16443     };
16444
16445     instance.bind(bindTo);
16446
16447     return instance;
16448 };
16449
16450 // backwards compat
16451 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16452  * Based on:
16453  * Ext JS Library 1.1.1
16454  * Copyright(c) 2006-2007, Ext JS, LLC.
16455  *
16456  * Originally Released Under LGPL - original licence link has changed is not relivant.
16457  *
16458  * Fork - LGPL
16459  * <script type="text/javascript">
16460  */
16461
16462 /**
16463  * @class Roo.state.Provider
16464  * Abstract base class for state provider implementations. This class provides methods
16465  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16466  * Provider interface.
16467  */
16468 Roo.state.Provider = function(){
16469     /**
16470      * @event statechange
16471      * Fires when a state change occurs.
16472      * @param {Provider} this This state provider
16473      * @param {String} key The state key which was changed
16474      * @param {String} value The encoded value for the state
16475      */
16476     this.addEvents({
16477         "statechange": true
16478     });
16479     this.state = {};
16480     Roo.state.Provider.superclass.constructor.call(this);
16481 };
16482 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16483     /**
16484      * Returns the current value for a key
16485      * @param {String} name The key name
16486      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16487      * @return {Mixed} The state data
16488      */
16489     get : function(name, defaultValue){
16490         return typeof this.state[name] == "undefined" ?
16491             defaultValue : this.state[name];
16492     },
16493     
16494     /**
16495      * Clears a value from the state
16496      * @param {String} name The key name
16497      */
16498     clear : function(name){
16499         delete this.state[name];
16500         this.fireEvent("statechange", this, name, null);
16501     },
16502     
16503     /**
16504      * Sets the value for a key
16505      * @param {String} name The key name
16506      * @param {Mixed} value The value to set
16507      */
16508     set : function(name, value){
16509         this.state[name] = value;
16510         this.fireEvent("statechange", this, name, value);
16511     },
16512     
16513     /**
16514      * Decodes a string previously encoded with {@link #encodeValue}.
16515      * @param {String} value The value to decode
16516      * @return {Mixed} The decoded value
16517      */
16518     decodeValue : function(cookie){
16519         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16520         var matches = re.exec(unescape(cookie));
16521         if(!matches || !matches[1]) {
16522             return; // non state cookie
16523         }
16524         var type = matches[1];
16525         var v = matches[2];
16526         switch(type){
16527             case "n":
16528                 return parseFloat(v);
16529             case "d":
16530                 return new Date(Date.parse(v));
16531             case "b":
16532                 return (v == "1");
16533             case "a":
16534                 var all = [];
16535                 var values = v.split("^");
16536                 for(var i = 0, len = values.length; i < len; i++){
16537                     all.push(this.decodeValue(values[i]));
16538                 }
16539                 return all;
16540            case "o":
16541                 var all = {};
16542                 var values = v.split("^");
16543                 for(var i = 0, len = values.length; i < len; i++){
16544                     var kv = values[i].split("=");
16545                     all[kv[0]] = this.decodeValue(kv[1]);
16546                 }
16547                 return all;
16548            default:
16549                 return v;
16550         }
16551     },
16552     
16553     /**
16554      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16555      * @param {Mixed} value The value to encode
16556      * @return {String} The encoded value
16557      */
16558     encodeValue : function(v){
16559         var enc;
16560         if(typeof v == "number"){
16561             enc = "n:" + v;
16562         }else if(typeof v == "boolean"){
16563             enc = "b:" + (v ? "1" : "0");
16564         }else if(v instanceof Date){
16565             enc = "d:" + v.toGMTString();
16566         }else if(v instanceof Array){
16567             var flat = "";
16568             for(var i = 0, len = v.length; i < len; i++){
16569                 flat += this.encodeValue(v[i]);
16570                 if(i != len-1) {
16571                     flat += "^";
16572                 }
16573             }
16574             enc = "a:" + flat;
16575         }else if(typeof v == "object"){
16576             var flat = "";
16577             for(var key in v){
16578                 if(typeof v[key] != "function"){
16579                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16580                 }
16581             }
16582             enc = "o:" + flat.substring(0, flat.length-1);
16583         }else{
16584             enc = "s:" + v;
16585         }
16586         return escape(enc);        
16587     }
16588 });
16589
16590 /*
16591  * Based on:
16592  * Ext JS Library 1.1.1
16593  * Copyright(c) 2006-2007, Ext JS, LLC.
16594  *
16595  * Originally Released Under LGPL - original licence link has changed is not relivant.
16596  *
16597  * Fork - LGPL
16598  * <script type="text/javascript">
16599  */
16600 /**
16601  * @class Roo.state.Manager
16602  * This is the global state manager. By default all components that are "state aware" check this class
16603  * for state information if you don't pass them a custom state provider. In order for this class
16604  * to be useful, it must be initialized with a provider when your application initializes.
16605  <pre><code>
16606 // in your initialization function
16607 init : function(){
16608    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16609    ...
16610    // supposed you have a {@link Roo.BorderLayout}
16611    var layout = new Roo.BorderLayout(...);
16612    layout.restoreState();
16613    // or a {Roo.BasicDialog}
16614    var dialog = new Roo.BasicDialog(...);
16615    dialog.restoreState();
16616  </code></pre>
16617  * @static
16618  */
16619 Roo.state.Manager = function(){
16620     var provider = new Roo.state.Provider();
16621     
16622     return {
16623         /**
16624          * Configures the default state provider for your application
16625          * @param {Provider} stateProvider The state provider to set
16626          */
16627         setProvider : function(stateProvider){
16628             provider = stateProvider;
16629         },
16630         
16631         /**
16632          * Returns the current value for a key
16633          * @param {String} name The key name
16634          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16635          * @return {Mixed} The state data
16636          */
16637         get : function(key, defaultValue){
16638             return provider.get(key, defaultValue);
16639         },
16640         
16641         /**
16642          * Sets the value for a key
16643          * @param {String} name The key name
16644          * @param {Mixed} value The state data
16645          */
16646          set : function(key, value){
16647             provider.set(key, value);
16648         },
16649         
16650         /**
16651          * Clears a value from the state
16652          * @param {String} name The key name
16653          */
16654         clear : function(key){
16655             provider.clear(key);
16656         },
16657         
16658         /**
16659          * Gets the currently configured state provider
16660          * @return {Provider} The state provider
16661          */
16662         getProvider : function(){
16663             return provider;
16664         }
16665     };
16666 }();
16667 /*
16668  * Based on:
16669  * Ext JS Library 1.1.1
16670  * Copyright(c) 2006-2007, Ext JS, LLC.
16671  *
16672  * Originally Released Under LGPL - original licence link has changed is not relivant.
16673  *
16674  * Fork - LGPL
16675  * <script type="text/javascript">
16676  */
16677 /**
16678  * @class Roo.state.CookieProvider
16679  * @extends Roo.state.Provider
16680  * The default Provider implementation which saves state via cookies.
16681  * <br />Usage:
16682  <pre><code>
16683    var cp = new Roo.state.CookieProvider({
16684        path: "/cgi-bin/",
16685        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16686        domain: "roojs.com"
16687    })
16688    Roo.state.Manager.setProvider(cp);
16689  </code></pre>
16690  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16691  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16692  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16693  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16694  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16695  * domain the page is running on including the 'www' like 'www.roojs.com')
16696  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16697  * @constructor
16698  * Create a new CookieProvider
16699  * @param {Object} config The configuration object
16700  */
16701 Roo.state.CookieProvider = function(config){
16702     Roo.state.CookieProvider.superclass.constructor.call(this);
16703     this.path = "/";
16704     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16705     this.domain = null;
16706     this.secure = false;
16707     Roo.apply(this, config);
16708     this.state = this.readCookies();
16709 };
16710
16711 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16712     // private
16713     set : function(name, value){
16714         if(typeof value == "undefined" || value === null){
16715             this.clear(name);
16716             return;
16717         }
16718         this.setCookie(name, value);
16719         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16720     },
16721
16722     // private
16723     clear : function(name){
16724         this.clearCookie(name);
16725         Roo.state.CookieProvider.superclass.clear.call(this, name);
16726     },
16727
16728     // private
16729     readCookies : function(){
16730         var cookies = {};
16731         var c = document.cookie + ";";
16732         var re = /\s?(.*?)=(.*?);/g;
16733         var matches;
16734         while((matches = re.exec(c)) != null){
16735             var name = matches[1];
16736             var value = matches[2];
16737             if(name && name.substring(0,3) == "ys-"){
16738                 cookies[name.substr(3)] = this.decodeValue(value);
16739             }
16740         }
16741         return cookies;
16742     },
16743
16744     // private
16745     setCookie : function(name, value){
16746         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16747            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16748            ((this.path == null) ? "" : ("; path=" + this.path)) +
16749            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16750            ((this.secure == true) ? "; secure" : "");
16751     },
16752
16753     // private
16754     clearCookie : function(name){
16755         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16756            ((this.path == null) ? "" : ("; path=" + this.path)) +
16757            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16758            ((this.secure == true) ? "; secure" : "");
16759     }
16760 });/*
16761  * Based on:
16762  * Ext JS Library 1.1.1
16763  * Copyright(c) 2006-2007, Ext JS, LLC.
16764  *
16765  * Originally Released Under LGPL - original licence link has changed is not relivant.
16766  *
16767  * Fork - LGPL
16768  * <script type="text/javascript">
16769  */
16770  
16771
16772 /**
16773  * @class Roo.ComponentMgr
16774  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16775  * @static
16776  */
16777 Roo.ComponentMgr = function(){
16778     var all = new Roo.util.MixedCollection();
16779
16780     return {
16781         /**
16782          * Registers a component.
16783          * @param {Roo.Component} c The component
16784          */
16785         register : function(c){
16786             all.add(c);
16787         },
16788
16789         /**
16790          * Unregisters a component.
16791          * @param {Roo.Component} c The component
16792          */
16793         unregister : function(c){
16794             all.remove(c);
16795         },
16796
16797         /**
16798          * Returns a component by id
16799          * @param {String} id The component id
16800          */
16801         get : function(id){
16802             return all.get(id);
16803         },
16804
16805         /**
16806          * Registers a function that will be called when a specified component is added to ComponentMgr
16807          * @param {String} id The component id
16808          * @param {Funtction} fn The callback function
16809          * @param {Object} scope The scope of the callback
16810          */
16811         onAvailable : function(id, fn, scope){
16812             all.on("add", function(index, o){
16813                 if(o.id == id){
16814                     fn.call(scope || o, o);
16815                     all.un("add", fn, scope);
16816                 }
16817             });
16818         }
16819     };
16820 }();/*
16821  * Based on:
16822  * Ext JS Library 1.1.1
16823  * Copyright(c) 2006-2007, Ext JS, LLC.
16824  *
16825  * Originally Released Under LGPL - original licence link has changed is not relivant.
16826  *
16827  * Fork - LGPL
16828  * <script type="text/javascript">
16829  */
16830  
16831 /**
16832  * @class Roo.Component
16833  * @extends Roo.util.Observable
16834  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16835  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16836  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16837  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16838  * All visual components (widgets) that require rendering into a layout should subclass Component.
16839  * @constructor
16840  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16841  * 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
16842  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16843  */
16844 Roo.Component = function(config){
16845     config = config || {};
16846     if(config.tagName || config.dom || typeof config == "string"){ // element object
16847         config = {el: config, id: config.id || config};
16848     }
16849     this.initialConfig = config;
16850
16851     Roo.apply(this, config);
16852     this.addEvents({
16853         /**
16854          * @event disable
16855          * Fires after the component is disabled.
16856              * @param {Roo.Component} this
16857              */
16858         disable : true,
16859         /**
16860          * @event enable
16861          * Fires after the component is enabled.
16862              * @param {Roo.Component} this
16863              */
16864         enable : true,
16865         /**
16866          * @event beforeshow
16867          * Fires before the component is shown.  Return false to stop the show.
16868              * @param {Roo.Component} this
16869              */
16870         beforeshow : true,
16871         /**
16872          * @event show
16873          * Fires after the component is shown.
16874              * @param {Roo.Component} this
16875              */
16876         show : true,
16877         /**
16878          * @event beforehide
16879          * Fires before the component is hidden. Return false to stop the hide.
16880              * @param {Roo.Component} this
16881              */
16882         beforehide : true,
16883         /**
16884          * @event hide
16885          * Fires after the component is hidden.
16886              * @param {Roo.Component} this
16887              */
16888         hide : true,
16889         /**
16890          * @event beforerender
16891          * Fires before the component is rendered. Return false to stop the render.
16892              * @param {Roo.Component} this
16893              */
16894         beforerender : true,
16895         /**
16896          * @event render
16897          * Fires after the component is rendered.
16898              * @param {Roo.Component} this
16899              */
16900         render : true,
16901         /**
16902          * @event beforedestroy
16903          * Fires before the component is destroyed. Return false to stop the destroy.
16904              * @param {Roo.Component} this
16905              */
16906         beforedestroy : true,
16907         /**
16908          * @event destroy
16909          * Fires after the component is destroyed.
16910              * @param {Roo.Component} this
16911              */
16912         destroy : true
16913     });
16914     if(!this.id){
16915         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16916     }
16917     Roo.ComponentMgr.register(this);
16918     Roo.Component.superclass.constructor.call(this);
16919     this.initComponent();
16920     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16921         this.render(this.renderTo);
16922         delete this.renderTo;
16923     }
16924 };
16925
16926 /** @private */
16927 Roo.Component.AUTO_ID = 1000;
16928
16929 Roo.extend(Roo.Component, Roo.util.Observable, {
16930     /**
16931      * @scope Roo.Component.prototype
16932      * @type {Boolean}
16933      * true if this component is hidden. Read-only.
16934      */
16935     hidden : false,
16936     /**
16937      * @type {Boolean}
16938      * true if this component is disabled. Read-only.
16939      */
16940     disabled : false,
16941     /**
16942      * @type {Boolean}
16943      * true if this component has been rendered. Read-only.
16944      */
16945     rendered : false,
16946     
16947     /** @cfg {String} disableClass
16948      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16949      */
16950     disabledClass : "x-item-disabled",
16951         /** @cfg {Boolean} allowDomMove
16952          * Whether the component can move the Dom node when rendering (defaults to true).
16953          */
16954     allowDomMove : true,
16955     /** @cfg {String} hideMode (display|visibility)
16956      * How this component should hidden. Supported values are
16957      * "visibility" (css visibility), "offsets" (negative offset position) and
16958      * "display" (css display) - defaults to "display".
16959      */
16960     hideMode: 'display',
16961
16962     /** @private */
16963     ctype : "Roo.Component",
16964
16965     /**
16966      * @cfg {String} actionMode 
16967      * which property holds the element that used for  hide() / show() / disable() / enable()
16968      * default is 'el' for forms you probably want to set this to fieldEl 
16969      */
16970     actionMode : "el",
16971
16972     /** @private */
16973     getActionEl : function(){
16974         return this[this.actionMode];
16975     },
16976
16977     initComponent : Roo.emptyFn,
16978     /**
16979      * If this is a lazy rendering component, render it to its container element.
16980      * @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.
16981      */
16982     render : function(container, position){
16983         
16984         if(this.rendered){
16985             return this;
16986         }
16987         
16988         if(this.fireEvent("beforerender", this) === false){
16989             return false;
16990         }
16991         
16992         if(!container && this.el){
16993             this.el = Roo.get(this.el);
16994             container = this.el.dom.parentNode;
16995             this.allowDomMove = false;
16996         }
16997         this.container = Roo.get(container);
16998         this.rendered = true;
16999         if(position !== undefined){
17000             if(typeof position == 'number'){
17001                 position = this.container.dom.childNodes[position];
17002             }else{
17003                 position = Roo.getDom(position);
17004             }
17005         }
17006         this.onRender(this.container, position || null);
17007         if(this.cls){
17008             this.el.addClass(this.cls);
17009             delete this.cls;
17010         }
17011         if(this.style){
17012             this.el.applyStyles(this.style);
17013             delete this.style;
17014         }
17015         this.fireEvent("render", this);
17016         this.afterRender(this.container);
17017         if(this.hidden){
17018             this.hide();
17019         }
17020         if(this.disabled){
17021             this.disable();
17022         }
17023
17024         return this;
17025         
17026     },
17027
17028     /** @private */
17029     // default function is not really useful
17030     onRender : function(ct, position){
17031         if(this.el){
17032             this.el = Roo.get(this.el);
17033             if(this.allowDomMove !== false){
17034                 ct.dom.insertBefore(this.el.dom, position);
17035             }
17036         }
17037     },
17038
17039     /** @private */
17040     getAutoCreate : function(){
17041         var cfg = typeof this.autoCreate == "object" ?
17042                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17043         if(this.id && !cfg.id){
17044             cfg.id = this.id;
17045         }
17046         return cfg;
17047     },
17048
17049     /** @private */
17050     afterRender : Roo.emptyFn,
17051
17052     /**
17053      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17054      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17055      */
17056     destroy : function(){
17057         if(this.fireEvent("beforedestroy", this) !== false){
17058             this.purgeListeners();
17059             this.beforeDestroy();
17060             if(this.rendered){
17061                 this.el.removeAllListeners();
17062                 this.el.remove();
17063                 if(this.actionMode == "container"){
17064                     this.container.remove();
17065                 }
17066             }
17067             this.onDestroy();
17068             Roo.ComponentMgr.unregister(this);
17069             this.fireEvent("destroy", this);
17070         }
17071     },
17072
17073         /** @private */
17074     beforeDestroy : function(){
17075
17076     },
17077
17078         /** @private */
17079         onDestroy : function(){
17080
17081     },
17082
17083     /**
17084      * Returns the underlying {@link Roo.Element}.
17085      * @return {Roo.Element} The element
17086      */
17087     getEl : function(){
17088         return this.el;
17089     },
17090
17091     /**
17092      * Returns the id of this component.
17093      * @return {String}
17094      */
17095     getId : function(){
17096         return this.id;
17097     },
17098
17099     /**
17100      * Try to focus this component.
17101      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17102      * @return {Roo.Component} this
17103      */
17104     focus : function(selectText){
17105         if(this.rendered){
17106             this.el.focus();
17107             if(selectText === true){
17108                 this.el.dom.select();
17109             }
17110         }
17111         return this;
17112     },
17113
17114     /** @private */
17115     blur : function(){
17116         if(this.rendered){
17117             this.el.blur();
17118         }
17119         return this;
17120     },
17121
17122     /**
17123      * Disable this component.
17124      * @return {Roo.Component} this
17125      */
17126     disable : function(){
17127         if(this.rendered){
17128             this.onDisable();
17129         }
17130         this.disabled = true;
17131         this.fireEvent("disable", this);
17132         return this;
17133     },
17134
17135         // private
17136     onDisable : function(){
17137         this.getActionEl().addClass(this.disabledClass);
17138         this.el.dom.disabled = true;
17139     },
17140
17141     /**
17142      * Enable this component.
17143      * @return {Roo.Component} this
17144      */
17145     enable : function(){
17146         if(this.rendered){
17147             this.onEnable();
17148         }
17149         this.disabled = false;
17150         this.fireEvent("enable", this);
17151         return this;
17152     },
17153
17154         // private
17155     onEnable : function(){
17156         this.getActionEl().removeClass(this.disabledClass);
17157         this.el.dom.disabled = false;
17158     },
17159
17160     /**
17161      * Convenience function for setting disabled/enabled by boolean.
17162      * @param {Boolean} disabled
17163      */
17164     setDisabled : function(disabled){
17165         this[disabled ? "disable" : "enable"]();
17166     },
17167
17168     /**
17169      * Show this component.
17170      * @return {Roo.Component} this
17171      */
17172     show: function(){
17173         if(this.fireEvent("beforeshow", this) !== false){
17174             this.hidden = false;
17175             if(this.rendered){
17176                 this.onShow();
17177             }
17178             this.fireEvent("show", this);
17179         }
17180         return this;
17181     },
17182
17183     // private
17184     onShow : function(){
17185         var ae = this.getActionEl();
17186         if(this.hideMode == 'visibility'){
17187             ae.dom.style.visibility = "visible";
17188         }else if(this.hideMode == 'offsets'){
17189             ae.removeClass('x-hidden');
17190         }else{
17191             ae.dom.style.display = "";
17192         }
17193     },
17194
17195     /**
17196      * Hide this component.
17197      * @return {Roo.Component} this
17198      */
17199     hide: function(){
17200         if(this.fireEvent("beforehide", this) !== false){
17201             this.hidden = true;
17202             if(this.rendered){
17203                 this.onHide();
17204             }
17205             this.fireEvent("hide", this);
17206         }
17207         return this;
17208     },
17209
17210     // private
17211     onHide : function(){
17212         var ae = this.getActionEl();
17213         if(this.hideMode == 'visibility'){
17214             ae.dom.style.visibility = "hidden";
17215         }else if(this.hideMode == 'offsets'){
17216             ae.addClass('x-hidden');
17217         }else{
17218             ae.dom.style.display = "none";
17219         }
17220     },
17221
17222     /**
17223      * Convenience function to hide or show this component by boolean.
17224      * @param {Boolean} visible True to show, false to hide
17225      * @return {Roo.Component} this
17226      */
17227     setVisible: function(visible){
17228         if(visible) {
17229             this.show();
17230         }else{
17231             this.hide();
17232         }
17233         return this;
17234     },
17235
17236     /**
17237      * Returns true if this component is visible.
17238      */
17239     isVisible : function(){
17240         return this.getActionEl().isVisible();
17241     },
17242
17243     cloneConfig : function(overrides){
17244         overrides = overrides || {};
17245         var id = overrides.id || Roo.id();
17246         var cfg = Roo.applyIf(overrides, this.initialConfig);
17247         cfg.id = id; // prevent dup id
17248         return new this.constructor(cfg);
17249     }
17250 });/*
17251  * Based on:
17252  * Ext JS Library 1.1.1
17253  * Copyright(c) 2006-2007, Ext JS, LLC.
17254  *
17255  * Originally Released Under LGPL - original licence link has changed is not relivant.
17256  *
17257  * Fork - LGPL
17258  * <script type="text/javascript">
17259  */
17260
17261 /**
17262  * @class Roo.BoxComponent
17263  * @extends Roo.Component
17264  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17265  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17266  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17267  * layout containers.
17268  * @constructor
17269  * @param {Roo.Element/String/Object} config The configuration options.
17270  */
17271 Roo.BoxComponent = function(config){
17272     Roo.Component.call(this, config);
17273     this.addEvents({
17274         /**
17275          * @event resize
17276          * Fires after the component is resized.
17277              * @param {Roo.Component} this
17278              * @param {Number} adjWidth The box-adjusted width that was set
17279              * @param {Number} adjHeight The box-adjusted height that was set
17280              * @param {Number} rawWidth The width that was originally specified
17281              * @param {Number} rawHeight The height that was originally specified
17282              */
17283         resize : true,
17284         /**
17285          * @event move
17286          * Fires after the component is moved.
17287              * @param {Roo.Component} this
17288              * @param {Number} x The new x position
17289              * @param {Number} y The new y position
17290              */
17291         move : true
17292     });
17293 };
17294
17295 Roo.extend(Roo.BoxComponent, Roo.Component, {
17296     // private, set in afterRender to signify that the component has been rendered
17297     boxReady : false,
17298     // private, used to defer height settings to subclasses
17299     deferHeight: false,
17300     /** @cfg {Number} width
17301      * width (optional) size of component
17302      */
17303      /** @cfg {Number} height
17304      * height (optional) size of component
17305      */
17306      
17307     /**
17308      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17309      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17310      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17311      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17312      * @return {Roo.BoxComponent} this
17313      */
17314     setSize : function(w, h){
17315         // support for standard size objects
17316         if(typeof w == 'object'){
17317             h = w.height;
17318             w = w.width;
17319         }
17320         // not rendered
17321         if(!this.boxReady){
17322             this.width = w;
17323             this.height = h;
17324             return this;
17325         }
17326
17327         // prevent recalcs when not needed
17328         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17329             return this;
17330         }
17331         this.lastSize = {width: w, height: h};
17332
17333         var adj = this.adjustSize(w, h);
17334         var aw = adj.width, ah = adj.height;
17335         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17336             var rz = this.getResizeEl();
17337             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17338                 rz.setSize(aw, ah);
17339             }else if(!this.deferHeight && ah !== undefined){
17340                 rz.setHeight(ah);
17341             }else if(aw !== undefined){
17342                 rz.setWidth(aw);
17343             }
17344             this.onResize(aw, ah, w, h);
17345             this.fireEvent('resize', this, aw, ah, w, h);
17346         }
17347         return this;
17348     },
17349
17350     /**
17351      * Gets the current size of the component's underlying element.
17352      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17353      */
17354     getSize : function(){
17355         return this.el.getSize();
17356     },
17357
17358     /**
17359      * Gets the current XY position of the component's underlying element.
17360      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17361      * @return {Array} The XY position of the element (e.g., [100, 200])
17362      */
17363     getPosition : function(local){
17364         if(local === true){
17365             return [this.el.getLeft(true), this.el.getTop(true)];
17366         }
17367         return this.xy || this.el.getXY();
17368     },
17369
17370     /**
17371      * Gets the current box measurements of the component's underlying element.
17372      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17373      * @returns {Object} box An object in the format {x, y, width, height}
17374      */
17375     getBox : function(local){
17376         var s = this.el.getSize();
17377         if(local){
17378             s.x = this.el.getLeft(true);
17379             s.y = this.el.getTop(true);
17380         }else{
17381             var xy = this.xy || this.el.getXY();
17382             s.x = xy[0];
17383             s.y = xy[1];
17384         }
17385         return s;
17386     },
17387
17388     /**
17389      * Sets the current box measurements of the component's underlying element.
17390      * @param {Object} box An object in the format {x, y, width, height}
17391      * @returns {Roo.BoxComponent} this
17392      */
17393     updateBox : function(box){
17394         this.setSize(box.width, box.height);
17395         this.setPagePosition(box.x, box.y);
17396         return this;
17397     },
17398
17399     // protected
17400     getResizeEl : function(){
17401         return this.resizeEl || this.el;
17402     },
17403
17404     // protected
17405     getPositionEl : function(){
17406         return this.positionEl || this.el;
17407     },
17408
17409     /**
17410      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17411      * This method fires the move event.
17412      * @param {Number} left The new left
17413      * @param {Number} top The new top
17414      * @returns {Roo.BoxComponent} this
17415      */
17416     setPosition : function(x, y){
17417         this.x = x;
17418         this.y = y;
17419         if(!this.boxReady){
17420             return this;
17421         }
17422         var adj = this.adjustPosition(x, y);
17423         var ax = adj.x, ay = adj.y;
17424
17425         var el = this.getPositionEl();
17426         if(ax !== undefined || ay !== undefined){
17427             if(ax !== undefined && ay !== undefined){
17428                 el.setLeftTop(ax, ay);
17429             }else if(ax !== undefined){
17430                 el.setLeft(ax);
17431             }else if(ay !== undefined){
17432                 el.setTop(ay);
17433             }
17434             this.onPosition(ax, ay);
17435             this.fireEvent('move', this, ax, ay);
17436         }
17437         return this;
17438     },
17439
17440     /**
17441      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17442      * This method fires the move event.
17443      * @param {Number} x The new x position
17444      * @param {Number} y The new y position
17445      * @returns {Roo.BoxComponent} this
17446      */
17447     setPagePosition : function(x, y){
17448         this.pageX = x;
17449         this.pageY = y;
17450         if(!this.boxReady){
17451             return;
17452         }
17453         if(x === undefined || y === undefined){ // cannot translate undefined points
17454             return;
17455         }
17456         var p = this.el.translatePoints(x, y);
17457         this.setPosition(p.left, p.top);
17458         return this;
17459     },
17460
17461     // private
17462     onRender : function(ct, position){
17463         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17464         if(this.resizeEl){
17465             this.resizeEl = Roo.get(this.resizeEl);
17466         }
17467         if(this.positionEl){
17468             this.positionEl = Roo.get(this.positionEl);
17469         }
17470     },
17471
17472     // private
17473     afterRender : function(){
17474         Roo.BoxComponent.superclass.afterRender.call(this);
17475         this.boxReady = true;
17476         this.setSize(this.width, this.height);
17477         if(this.x || this.y){
17478             this.setPosition(this.x, this.y);
17479         }
17480         if(this.pageX || this.pageY){
17481             this.setPagePosition(this.pageX, this.pageY);
17482         }
17483     },
17484
17485     /**
17486      * Force the component's size to recalculate based on the underlying element's current height and width.
17487      * @returns {Roo.BoxComponent} this
17488      */
17489     syncSize : function(){
17490         delete this.lastSize;
17491         this.setSize(this.el.getWidth(), this.el.getHeight());
17492         return this;
17493     },
17494
17495     /**
17496      * Called after the component is resized, this method is empty by default but can be implemented by any
17497      * subclass that needs to perform custom logic after a resize occurs.
17498      * @param {Number} adjWidth The box-adjusted width that was set
17499      * @param {Number} adjHeight The box-adjusted height that was set
17500      * @param {Number} rawWidth The width that was originally specified
17501      * @param {Number} rawHeight The height that was originally specified
17502      */
17503     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17504
17505     },
17506
17507     /**
17508      * Called after the component is moved, this method is empty by default but can be implemented by any
17509      * subclass that needs to perform custom logic after a move occurs.
17510      * @param {Number} x The new x position
17511      * @param {Number} y The new y position
17512      */
17513     onPosition : function(x, y){
17514
17515     },
17516
17517     // private
17518     adjustSize : function(w, h){
17519         if(this.autoWidth){
17520             w = 'auto';
17521         }
17522         if(this.autoHeight){
17523             h = 'auto';
17524         }
17525         return {width : w, height: h};
17526     },
17527
17528     // private
17529     adjustPosition : function(x, y){
17530         return {x : x, y: y};
17531     }
17532 });/*
17533  * Based on:
17534  * Ext JS Library 1.1.1
17535  * Copyright(c) 2006-2007, Ext JS, LLC.
17536  *
17537  * Originally Released Under LGPL - original licence link has changed is not relivant.
17538  *
17539  * Fork - LGPL
17540  * <script type="text/javascript">
17541  */
17542  (function(){ 
17543 /**
17544  * @class Roo.Layer
17545  * @extends Roo.Element
17546  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17547  * automatic maintaining of shadow/shim positions.
17548  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17549  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17550  * you can pass a string with a CSS class name. False turns off the shadow.
17551  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17552  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17553  * @cfg {String} cls CSS class to add to the element
17554  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17555  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17556  * @constructor
17557  * @param {Object} config An object with config options.
17558  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17559  */
17560
17561 Roo.Layer = function(config, existingEl){
17562     config = config || {};
17563     var dh = Roo.DomHelper;
17564     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17565     if(existingEl){
17566         this.dom = Roo.getDom(existingEl);
17567     }
17568     if(!this.dom){
17569         var o = config.dh || {tag: "div", cls: "x-layer"};
17570         this.dom = dh.append(pel, o);
17571     }
17572     if(config.cls){
17573         this.addClass(config.cls);
17574     }
17575     this.constrain = config.constrain !== false;
17576     this.visibilityMode = Roo.Element.VISIBILITY;
17577     if(config.id){
17578         this.id = this.dom.id = config.id;
17579     }else{
17580         this.id = Roo.id(this.dom);
17581     }
17582     this.zindex = config.zindex || this.getZIndex();
17583     this.position("absolute", this.zindex);
17584     if(config.shadow){
17585         this.shadowOffset = config.shadowOffset || 4;
17586         this.shadow = new Roo.Shadow({
17587             offset : this.shadowOffset,
17588             mode : config.shadow
17589         });
17590     }else{
17591         this.shadowOffset = 0;
17592     }
17593     this.useShim = config.shim !== false && Roo.useShims;
17594     this.useDisplay = config.useDisplay;
17595     this.hide();
17596 };
17597
17598 var supr = Roo.Element.prototype;
17599
17600 // shims are shared among layer to keep from having 100 iframes
17601 var shims = [];
17602
17603 Roo.extend(Roo.Layer, Roo.Element, {
17604
17605     getZIndex : function(){
17606         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17607     },
17608
17609     getShim : function(){
17610         if(!this.useShim){
17611             return null;
17612         }
17613         if(this.shim){
17614             return this.shim;
17615         }
17616         var shim = shims.shift();
17617         if(!shim){
17618             shim = this.createShim();
17619             shim.enableDisplayMode('block');
17620             shim.dom.style.display = 'none';
17621             shim.dom.style.visibility = 'visible';
17622         }
17623         var pn = this.dom.parentNode;
17624         if(shim.dom.parentNode != pn){
17625             pn.insertBefore(shim.dom, this.dom);
17626         }
17627         shim.setStyle('z-index', this.getZIndex()-2);
17628         this.shim = shim;
17629         return shim;
17630     },
17631
17632     hideShim : function(){
17633         if(this.shim){
17634             this.shim.setDisplayed(false);
17635             shims.push(this.shim);
17636             delete this.shim;
17637         }
17638     },
17639
17640     disableShadow : function(){
17641         if(this.shadow){
17642             this.shadowDisabled = true;
17643             this.shadow.hide();
17644             this.lastShadowOffset = this.shadowOffset;
17645             this.shadowOffset = 0;
17646         }
17647     },
17648
17649     enableShadow : function(show){
17650         if(this.shadow){
17651             this.shadowDisabled = false;
17652             this.shadowOffset = this.lastShadowOffset;
17653             delete this.lastShadowOffset;
17654             if(show){
17655                 this.sync(true);
17656             }
17657         }
17658     },
17659
17660     // private
17661     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17662     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17663     sync : function(doShow){
17664         var sw = this.shadow;
17665         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17666             var sh = this.getShim();
17667
17668             var w = this.getWidth(),
17669                 h = this.getHeight();
17670
17671             var l = this.getLeft(true),
17672                 t = this.getTop(true);
17673
17674             if(sw && !this.shadowDisabled){
17675                 if(doShow && !sw.isVisible()){
17676                     sw.show(this);
17677                 }else{
17678                     sw.realign(l, t, w, h);
17679                 }
17680                 if(sh){
17681                     if(doShow){
17682                        sh.show();
17683                     }
17684                     // fit the shim behind the shadow, so it is shimmed too
17685                     var a = sw.adjusts, s = sh.dom.style;
17686                     s.left = (Math.min(l, l+a.l))+"px";
17687                     s.top = (Math.min(t, t+a.t))+"px";
17688                     s.width = (w+a.w)+"px";
17689                     s.height = (h+a.h)+"px";
17690                 }
17691             }else if(sh){
17692                 if(doShow){
17693                    sh.show();
17694                 }
17695                 sh.setSize(w, h);
17696                 sh.setLeftTop(l, t);
17697             }
17698             
17699         }
17700     },
17701
17702     // private
17703     destroy : function(){
17704         this.hideShim();
17705         if(this.shadow){
17706             this.shadow.hide();
17707         }
17708         this.removeAllListeners();
17709         var pn = this.dom.parentNode;
17710         if(pn){
17711             pn.removeChild(this.dom);
17712         }
17713         Roo.Element.uncache(this.id);
17714     },
17715
17716     remove : function(){
17717         this.destroy();
17718     },
17719
17720     // private
17721     beginUpdate : function(){
17722         this.updating = true;
17723     },
17724
17725     // private
17726     endUpdate : function(){
17727         this.updating = false;
17728         this.sync(true);
17729     },
17730
17731     // private
17732     hideUnders : function(negOffset){
17733         if(this.shadow){
17734             this.shadow.hide();
17735         }
17736         this.hideShim();
17737     },
17738
17739     // private
17740     constrainXY : function(){
17741         if(this.constrain){
17742             var vw = Roo.lib.Dom.getViewWidth(),
17743                 vh = Roo.lib.Dom.getViewHeight();
17744             var s = Roo.get(document).getScroll();
17745
17746             var xy = this.getXY();
17747             var x = xy[0], y = xy[1];   
17748             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17749             // only move it if it needs it
17750             var moved = false;
17751             // first validate right/bottom
17752             if((x + w) > vw+s.left){
17753                 x = vw - w - this.shadowOffset;
17754                 moved = true;
17755             }
17756             if((y + h) > vh+s.top){
17757                 y = vh - h - this.shadowOffset;
17758                 moved = true;
17759             }
17760             // then make sure top/left isn't negative
17761             if(x < s.left){
17762                 x = s.left;
17763                 moved = true;
17764             }
17765             if(y < s.top){
17766                 y = s.top;
17767                 moved = true;
17768             }
17769             if(moved){
17770                 if(this.avoidY){
17771                     var ay = this.avoidY;
17772                     if(y <= ay && (y+h) >= ay){
17773                         y = ay-h-5;   
17774                     }
17775                 }
17776                 xy = [x, y];
17777                 this.storeXY(xy);
17778                 supr.setXY.call(this, xy);
17779                 this.sync();
17780             }
17781         }
17782     },
17783
17784     isVisible : function(){
17785         return this.visible;    
17786     },
17787
17788     // private
17789     showAction : function(){
17790         this.visible = true; // track visibility to prevent getStyle calls
17791         if(this.useDisplay === true){
17792             this.setDisplayed("");
17793         }else if(this.lastXY){
17794             supr.setXY.call(this, this.lastXY);
17795         }else if(this.lastLT){
17796             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17797         }
17798     },
17799
17800     // private
17801     hideAction : function(){
17802         this.visible = false;
17803         if(this.useDisplay === true){
17804             this.setDisplayed(false);
17805         }else{
17806             this.setLeftTop(-10000,-10000);
17807         }
17808     },
17809
17810     // overridden Element method
17811     setVisible : function(v, a, d, c, e){
17812         if(v){
17813             this.showAction();
17814         }
17815         if(a && v){
17816             var cb = function(){
17817                 this.sync(true);
17818                 if(c){
17819                     c();
17820                 }
17821             }.createDelegate(this);
17822             supr.setVisible.call(this, true, true, d, cb, e);
17823         }else{
17824             if(!v){
17825                 this.hideUnders(true);
17826             }
17827             var cb = c;
17828             if(a){
17829                 cb = function(){
17830                     this.hideAction();
17831                     if(c){
17832                         c();
17833                     }
17834                 }.createDelegate(this);
17835             }
17836             supr.setVisible.call(this, v, a, d, cb, e);
17837             if(v){
17838                 this.sync(true);
17839             }else if(!a){
17840                 this.hideAction();
17841             }
17842         }
17843     },
17844
17845     storeXY : function(xy){
17846         delete this.lastLT;
17847         this.lastXY = xy;
17848     },
17849
17850     storeLeftTop : function(left, top){
17851         delete this.lastXY;
17852         this.lastLT = [left, top];
17853     },
17854
17855     // private
17856     beforeFx : function(){
17857         this.beforeAction();
17858         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17859     },
17860
17861     // private
17862     afterFx : function(){
17863         Roo.Layer.superclass.afterFx.apply(this, arguments);
17864         this.sync(this.isVisible());
17865     },
17866
17867     // private
17868     beforeAction : function(){
17869         if(!this.updating && this.shadow){
17870             this.shadow.hide();
17871         }
17872     },
17873
17874     // overridden Element method
17875     setLeft : function(left){
17876         this.storeLeftTop(left, this.getTop(true));
17877         supr.setLeft.apply(this, arguments);
17878         this.sync();
17879     },
17880
17881     setTop : function(top){
17882         this.storeLeftTop(this.getLeft(true), top);
17883         supr.setTop.apply(this, arguments);
17884         this.sync();
17885     },
17886
17887     setLeftTop : function(left, top){
17888         this.storeLeftTop(left, top);
17889         supr.setLeftTop.apply(this, arguments);
17890         this.sync();
17891     },
17892
17893     setXY : function(xy, a, d, c, e){
17894         this.fixDisplay();
17895         this.beforeAction();
17896         this.storeXY(xy);
17897         var cb = this.createCB(c);
17898         supr.setXY.call(this, xy, a, d, cb, e);
17899         if(!a){
17900             cb();
17901         }
17902     },
17903
17904     // private
17905     createCB : function(c){
17906         var el = this;
17907         return function(){
17908             el.constrainXY();
17909             el.sync(true);
17910             if(c){
17911                 c();
17912             }
17913         };
17914     },
17915
17916     // overridden Element method
17917     setX : function(x, a, d, c, e){
17918         this.setXY([x, this.getY()], a, d, c, e);
17919     },
17920
17921     // overridden Element method
17922     setY : function(y, a, d, c, e){
17923         this.setXY([this.getX(), y], a, d, c, e);
17924     },
17925
17926     // overridden Element method
17927     setSize : function(w, h, a, d, c, e){
17928         this.beforeAction();
17929         var cb = this.createCB(c);
17930         supr.setSize.call(this, w, h, a, d, cb, e);
17931         if(!a){
17932             cb();
17933         }
17934     },
17935
17936     // overridden Element method
17937     setWidth : function(w, a, d, c, e){
17938         this.beforeAction();
17939         var cb = this.createCB(c);
17940         supr.setWidth.call(this, w, a, d, cb, e);
17941         if(!a){
17942             cb();
17943         }
17944     },
17945
17946     // overridden Element method
17947     setHeight : function(h, a, d, c, e){
17948         this.beforeAction();
17949         var cb = this.createCB(c);
17950         supr.setHeight.call(this, h, a, d, cb, e);
17951         if(!a){
17952             cb();
17953         }
17954     },
17955
17956     // overridden Element method
17957     setBounds : function(x, y, w, h, a, d, c, e){
17958         this.beforeAction();
17959         var cb = this.createCB(c);
17960         if(!a){
17961             this.storeXY([x, y]);
17962             supr.setXY.call(this, [x, y]);
17963             supr.setSize.call(this, w, h, a, d, cb, e);
17964             cb();
17965         }else{
17966             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17967         }
17968         return this;
17969     },
17970     
17971     /**
17972      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17973      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17974      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17975      * @param {Number} zindex The new z-index to set
17976      * @return {this} The Layer
17977      */
17978     setZIndex : function(zindex){
17979         this.zindex = zindex;
17980         this.setStyle("z-index", zindex + 2);
17981         if(this.shadow){
17982             this.shadow.setZIndex(zindex + 1);
17983         }
17984         if(this.shim){
17985             this.shim.setStyle("z-index", zindex);
17986         }
17987     }
17988 });
17989 })();/*
17990  * Original code for Roojs - LGPL
17991  * <script type="text/javascript">
17992  */
17993  
17994 /**
17995  * @class Roo.XComponent
17996  * A delayed Element creator...
17997  * Or a way to group chunks of interface together.
17998  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17999  *  used in conjunction with XComponent.build() it will create an instance of each element,
18000  *  then call addxtype() to build the User interface.
18001  * 
18002  * Mypart.xyx = new Roo.XComponent({
18003
18004     parent : 'Mypart.xyz', // empty == document.element.!!
18005     order : '001',
18006     name : 'xxxx'
18007     region : 'xxxx'
18008     disabled : function() {} 
18009      
18010     tree : function() { // return an tree of xtype declared components
18011         var MODULE = this;
18012         return 
18013         {
18014             xtype : 'NestedLayoutPanel',
18015             // technicall
18016         }
18017      ]
18018  *})
18019  *
18020  *
18021  * It can be used to build a big heiracy, with parent etc.
18022  * or you can just use this to render a single compoent to a dom element
18023  * MYPART.render(Roo.Element | String(id) | dom_element )
18024  *
18025  *
18026  * Usage patterns.
18027  *
18028  * Classic Roo
18029  *
18030  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18031  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18032  *
18033  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18034  *
18035  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18036  * - if mulitple topModules exist, the last one is defined as the top module.
18037  *
18038  * Embeded Roo
18039  * 
18040  * When the top level or multiple modules are to embedded into a existing HTML page,
18041  * the parent element can container '#id' of the element where the module will be drawn.
18042  *
18043  * Bootstrap Roo
18044  *
18045  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18046  * it relies more on a include mechanism, where sub modules are included into an outer page.
18047  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18048  * 
18049  * Bootstrap Roo Included elements
18050  *
18051  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18052  * hence confusing the component builder as it thinks there are multiple top level elements. 
18053  *
18054  * String Over-ride & Translations
18055  *
18056  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18057  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18058  * are needed. @see Roo.XComponent.overlayString  
18059  * 
18060  * 
18061  * 
18062  * @extends Roo.util.Observable
18063  * @constructor
18064  * @param cfg {Object} configuration of component
18065  * 
18066  */
18067 Roo.XComponent = function(cfg) {
18068     Roo.apply(this, cfg);
18069     this.addEvents({ 
18070         /**
18071              * @event built
18072              * Fires when this the componnt is built
18073              * @param {Roo.XComponent} c the component
18074              */
18075         'built' : true
18076         
18077     });
18078     this.region = this.region || 'center'; // default..
18079     Roo.XComponent.register(this);
18080     this.modules = false;
18081     this.el = false; // where the layout goes..
18082     
18083     
18084 }
18085 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18086     /**
18087      * @property el
18088      * The created element (with Roo.factory())
18089      * @type {Roo.Layout}
18090      */
18091     el  : false,
18092     
18093     /**
18094      * @property el
18095      * for BC  - use el in new code
18096      * @type {Roo.Layout}
18097      */
18098     panel : false,
18099     
18100     /**
18101      * @property layout
18102      * for BC  - use el in new code
18103      * @type {Roo.Layout}
18104      */
18105     layout : false,
18106     
18107      /**
18108      * @cfg {Function|boolean} disabled
18109      * If this module is disabled by some rule, return true from the funtion
18110      */
18111     disabled : false,
18112     
18113     /**
18114      * @cfg {String} parent 
18115      * Name of parent element which it get xtype added to..
18116      */
18117     parent: false,
18118     
18119     /**
18120      * @cfg {String} order
18121      * Used to set the order in which elements are created (usefull for multiple tabs)
18122      */
18123     
18124     order : false,
18125     /**
18126      * @cfg {String} name
18127      * String to display while loading.
18128      */
18129     name : false,
18130     /**
18131      * @cfg {String} region
18132      * Region to render component to (defaults to center)
18133      */
18134     region : 'center',
18135     
18136     /**
18137      * @cfg {Array} items
18138      * A single item array - the first element is the root of the tree..
18139      * It's done this way to stay compatible with the Xtype system...
18140      */
18141     items : false,
18142     
18143     /**
18144      * @property _tree
18145      * The method that retuns the tree of parts that make up this compoennt 
18146      * @type {function}
18147      */
18148     _tree  : false,
18149     
18150      /**
18151      * render
18152      * render element to dom or tree
18153      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18154      */
18155     
18156     render : function(el)
18157     {
18158         
18159         el = el || false;
18160         var hp = this.parent ? 1 : 0;
18161         Roo.debug &&  Roo.log(this);
18162         
18163         var tree = this._tree ? this._tree() : this.tree();
18164
18165         
18166         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18167             // if parent is a '#.....' string, then let's use that..
18168             var ename = this.parent.substr(1);
18169             this.parent = false;
18170             Roo.debug && Roo.log(ename);
18171             switch (ename) {
18172                 case 'bootstrap-body':
18173                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18174                         // this is the BorderLayout standard?
18175                        this.parent = { el : true };
18176                        break;
18177                     }
18178                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18179                         // need to insert stuff...
18180                         this.parent =  {
18181                              el : new Roo.bootstrap.layout.Border({
18182                                  el : document.body, 
18183                      
18184                                  center: {
18185                                     titlebar: false,
18186                                     autoScroll:false,
18187                                     closeOnTab: true,
18188                                     tabPosition: 'top',
18189                                       //resizeTabs: true,
18190                                     alwaysShowTabs: true,
18191                                     hideTabs: false
18192                                      //minTabWidth: 140
18193                                  }
18194                              })
18195                         
18196                          };
18197                          break;
18198                     }
18199                          
18200                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18201                         this.parent = { el :  new  Roo.bootstrap.Body() };
18202                         Roo.debug && Roo.log("setting el to doc body");
18203                          
18204                     } else {
18205                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18206                     }
18207                     break;
18208                 case 'bootstrap':
18209                     this.parent = { el : true};
18210                     // fall through
18211                 default:
18212                     el = Roo.get(ename);
18213                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18214                         this.parent = { el : true};
18215                     }
18216                     
18217                     break;
18218             }
18219                 
18220             
18221             if (!el && !this.parent) {
18222                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18223                 return;
18224             }
18225         }
18226         
18227         Roo.debug && Roo.log("EL:");
18228         Roo.debug && Roo.log(el);
18229         Roo.debug && Roo.log("this.parent.el:");
18230         Roo.debug && Roo.log(this.parent.el);
18231         
18232
18233         // altertive root elements ??? - we need a better way to indicate these.
18234         var is_alt = Roo.XComponent.is_alt ||
18235                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18236                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18237                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18238         
18239         
18240         
18241         if (!this.parent && is_alt) {
18242             //el = Roo.get(document.body);
18243             this.parent = { el : true };
18244         }
18245             
18246             
18247         
18248         if (!this.parent) {
18249             
18250             Roo.debug && Roo.log("no parent - creating one");
18251             
18252             el = el ? Roo.get(el) : false;      
18253             
18254             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18255                 
18256                 this.parent =  {
18257                     el : new Roo.bootstrap.layout.Border({
18258                         el: el || document.body,
18259                     
18260                         center: {
18261                             titlebar: false,
18262                             autoScroll:false,
18263                             closeOnTab: true,
18264                             tabPosition: 'top',
18265                              //resizeTabs: true,
18266                             alwaysShowTabs: false,
18267                             hideTabs: true,
18268                             minTabWidth: 140,
18269                             overflow: 'visible'
18270                          }
18271                      })
18272                 };
18273             } else {
18274             
18275                 // it's a top level one..
18276                 this.parent =  {
18277                     el : new Roo.BorderLayout(el || document.body, {
18278                         center: {
18279                             titlebar: false,
18280                             autoScroll:false,
18281                             closeOnTab: true,
18282                             tabPosition: 'top',
18283                              //resizeTabs: true,
18284                             alwaysShowTabs: el && hp? false :  true,
18285                             hideTabs: el || !hp ? true :  false,
18286                             minTabWidth: 140
18287                          }
18288                     })
18289                 };
18290             }
18291         }
18292         
18293         if (!this.parent.el) {
18294                 // probably an old style ctor, which has been disabled.
18295                 return;
18296
18297         }
18298                 // The 'tree' method is  '_tree now' 
18299             
18300         tree.region = tree.region || this.region;
18301         var is_body = false;
18302         if (this.parent.el === true) {
18303             // bootstrap... - body..
18304             if (el) {
18305                 tree.el = el;
18306             }
18307             this.parent.el = Roo.factory(tree);
18308             is_body = true;
18309         }
18310         
18311         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18312         this.fireEvent('built', this);
18313         
18314         this.panel = this.el;
18315         this.layout = this.panel.layout;
18316         this.parentLayout = this.parent.layout  || false;  
18317          
18318     }
18319     
18320 });
18321
18322 Roo.apply(Roo.XComponent, {
18323     /**
18324      * @property  hideProgress
18325      * true to disable the building progress bar.. usefull on single page renders.
18326      * @type Boolean
18327      */
18328     hideProgress : false,
18329     /**
18330      * @property  buildCompleted
18331      * True when the builder has completed building the interface.
18332      * @type Boolean
18333      */
18334     buildCompleted : false,
18335      
18336     /**
18337      * @property  topModule
18338      * the upper most module - uses document.element as it's constructor.
18339      * @type Object
18340      */
18341      
18342     topModule  : false,
18343       
18344     /**
18345      * @property  modules
18346      * array of modules to be created by registration system.
18347      * @type {Array} of Roo.XComponent
18348      */
18349     
18350     modules : [],
18351     /**
18352      * @property  elmodules
18353      * array of modules to be created by which use #ID 
18354      * @type {Array} of Roo.XComponent
18355      */
18356      
18357     elmodules : [],
18358
18359      /**
18360      * @property  is_alt
18361      * Is an alternative Root - normally used by bootstrap or other systems,
18362      *    where the top element in the tree can wrap 'body' 
18363      * @type {boolean}  (default false)
18364      */
18365      
18366     is_alt : false,
18367     /**
18368      * @property  build_from_html
18369      * Build elements from html - used by bootstrap HTML stuff 
18370      *    - this is cleared after build is completed
18371      * @type {boolean}    (default false)
18372      */
18373      
18374     build_from_html : false,
18375     /**
18376      * Register components to be built later.
18377      *
18378      * This solves the following issues
18379      * - Building is not done on page load, but after an authentication process has occured.
18380      * - Interface elements are registered on page load
18381      * - Parent Interface elements may not be loaded before child, so this handles that..
18382      * 
18383      *
18384      * example:
18385      * 
18386      * MyApp.register({
18387           order : '000001',
18388           module : 'Pman.Tab.projectMgr',
18389           region : 'center',
18390           parent : 'Pman.layout',
18391           disabled : false,  // or use a function..
18392         })
18393      
18394      * * @param {Object} details about module
18395      */
18396     register : function(obj) {
18397                 
18398         Roo.XComponent.event.fireEvent('register', obj);
18399         switch(typeof(obj.disabled) ) {
18400                 
18401             case 'undefined':
18402                 break;
18403             
18404             case 'function':
18405                 if ( obj.disabled() ) {
18406                         return;
18407                 }
18408                 break;
18409             
18410             default:
18411                 if (obj.disabled || obj.region == '#disabled') {
18412                         return;
18413                 }
18414                 break;
18415         }
18416                 
18417         this.modules.push(obj);
18418          
18419     },
18420     /**
18421      * convert a string to an object..
18422      * eg. 'AAA.BBB' -> finds AAA.BBB
18423
18424      */
18425     
18426     toObject : function(str)
18427     {
18428         if (!str || typeof(str) == 'object') {
18429             return str;
18430         }
18431         if (str.substring(0,1) == '#') {
18432             return str;
18433         }
18434
18435         var ar = str.split('.');
18436         var rt, o;
18437         rt = ar.shift();
18438             /** eval:var:o */
18439         try {
18440             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18441         } catch (e) {
18442             throw "Module not found : " + str;
18443         }
18444         
18445         if (o === false) {
18446             throw "Module not found : " + str;
18447         }
18448         Roo.each(ar, function(e) {
18449             if (typeof(o[e]) == 'undefined') {
18450                 throw "Module not found : " + str;
18451             }
18452             o = o[e];
18453         });
18454         
18455         return o;
18456         
18457     },
18458     
18459     
18460     /**
18461      * move modules into their correct place in the tree..
18462      * 
18463      */
18464     preBuild : function ()
18465     {
18466         var _t = this;
18467         Roo.each(this.modules , function (obj)
18468         {
18469             Roo.XComponent.event.fireEvent('beforebuild', obj);
18470             
18471             var opar = obj.parent;
18472             try { 
18473                 obj.parent = this.toObject(opar);
18474             } catch(e) {
18475                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18476                 return;
18477             }
18478             
18479             if (!obj.parent) {
18480                 Roo.debug && Roo.log("GOT top level module");
18481                 Roo.debug && Roo.log(obj);
18482                 obj.modules = new Roo.util.MixedCollection(false, 
18483                     function(o) { return o.order + '' }
18484                 );
18485                 this.topModule = obj;
18486                 return;
18487             }
18488                         // parent is a string (usually a dom element name..)
18489             if (typeof(obj.parent) == 'string') {
18490                 this.elmodules.push(obj);
18491                 return;
18492             }
18493             if (obj.parent.constructor != Roo.XComponent) {
18494                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18495             }
18496             if (!obj.parent.modules) {
18497                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18498                     function(o) { return o.order + '' }
18499                 );
18500             }
18501             if (obj.parent.disabled) {
18502                 obj.disabled = true;
18503             }
18504             obj.parent.modules.add(obj);
18505         }, this);
18506     },
18507     
18508      /**
18509      * make a list of modules to build.
18510      * @return {Array} list of modules. 
18511      */ 
18512     
18513     buildOrder : function()
18514     {
18515         var _this = this;
18516         var cmp = function(a,b) {   
18517             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18518         };
18519         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18520             throw "No top level modules to build";
18521         }
18522         
18523         // make a flat list in order of modules to build.
18524         var mods = this.topModule ? [ this.topModule ] : [];
18525                 
18526         
18527         // elmodules (is a list of DOM based modules )
18528         Roo.each(this.elmodules, function(e) {
18529             mods.push(e);
18530             if (!this.topModule &&
18531                 typeof(e.parent) == 'string' &&
18532                 e.parent.substring(0,1) == '#' &&
18533                 Roo.get(e.parent.substr(1))
18534                ) {
18535                 
18536                 _this.topModule = e;
18537             }
18538             
18539         });
18540
18541         
18542         // add modules to their parents..
18543         var addMod = function(m) {
18544             Roo.debug && Roo.log("build Order: add: " + m.name);
18545                 
18546             mods.push(m);
18547             if (m.modules && !m.disabled) {
18548                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18549                 m.modules.keySort('ASC',  cmp );
18550                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18551     
18552                 m.modules.each(addMod);
18553             } else {
18554                 Roo.debug && Roo.log("build Order: no child modules");
18555             }
18556             // not sure if this is used any more..
18557             if (m.finalize) {
18558                 m.finalize.name = m.name + " (clean up) ";
18559                 mods.push(m.finalize);
18560             }
18561             
18562         }
18563         if (this.topModule && this.topModule.modules) { 
18564             this.topModule.modules.keySort('ASC',  cmp );
18565             this.topModule.modules.each(addMod);
18566         } 
18567         return mods;
18568     },
18569     
18570      /**
18571      * Build the registered modules.
18572      * @param {Object} parent element.
18573      * @param {Function} optional method to call after module has been added.
18574      * 
18575      */ 
18576    
18577     build : function(opts) 
18578     {
18579         
18580         if (typeof(opts) != 'undefined') {
18581             Roo.apply(this,opts);
18582         }
18583         
18584         this.preBuild();
18585         var mods = this.buildOrder();
18586       
18587         //this.allmods = mods;
18588         //Roo.debug && Roo.log(mods);
18589         //return;
18590         if (!mods.length) { // should not happen
18591             throw "NO modules!!!";
18592         }
18593         
18594         
18595         var msg = "Building Interface...";
18596         // flash it up as modal - so we store the mask!?
18597         if (!this.hideProgress && Roo.MessageBox) {
18598             Roo.MessageBox.show({ title: 'loading' });
18599             Roo.MessageBox.show({
18600                title: "Please wait...",
18601                msg: msg,
18602                width:450,
18603                progress:true,
18604                buttons : false,
18605                closable:false,
18606                modal: false
18607               
18608             });
18609         }
18610         var total = mods.length;
18611         
18612         var _this = this;
18613         var progressRun = function() {
18614             if (!mods.length) {
18615                 Roo.debug && Roo.log('hide?');
18616                 if (!this.hideProgress && Roo.MessageBox) {
18617                     Roo.MessageBox.hide();
18618                 }
18619                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18620                 
18621                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18622                 
18623                 // THE END...
18624                 return false;   
18625             }
18626             
18627             var m = mods.shift();
18628             
18629             
18630             Roo.debug && Roo.log(m);
18631             // not sure if this is supported any more.. - modules that are are just function
18632             if (typeof(m) == 'function') { 
18633                 m.call(this);
18634                 return progressRun.defer(10, _this);
18635             } 
18636             
18637             
18638             msg = "Building Interface " + (total  - mods.length) + 
18639                     " of " + total + 
18640                     (m.name ? (' - ' + m.name) : '');
18641                         Roo.debug && Roo.log(msg);
18642             if (!_this.hideProgress &&  Roo.MessageBox) { 
18643                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18644             }
18645             
18646          
18647             // is the module disabled?
18648             var disabled = (typeof(m.disabled) == 'function') ?
18649                 m.disabled.call(m.module.disabled) : m.disabled;    
18650             
18651             
18652             if (disabled) {
18653                 return progressRun(); // we do not update the display!
18654             }
18655             
18656             // now build 
18657             
18658                         
18659                         
18660             m.render();
18661             // it's 10 on top level, and 1 on others??? why...
18662             return progressRun.defer(10, _this);
18663              
18664         }
18665         progressRun.defer(1, _this);
18666      
18667         
18668         
18669     },
18670     /**
18671      * Overlay a set of modified strings onto a component
18672      * This is dependant on our builder exporting the strings and 'named strings' elements.
18673      * 
18674      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18675      * @param {Object} associative array of 'named' string and it's new value.
18676      * 
18677      */
18678         overlayStrings : function( component, strings )
18679     {
18680         if (typeof(component['_named_strings']) == 'undefined') {
18681             throw "ERROR: component does not have _named_strings";
18682         }
18683         for ( var k in strings ) {
18684             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18685             if (md !== false) {
18686                 component['_strings'][md] = strings[k];
18687             } else {
18688                 Roo.log('could not find named string: ' + k + ' in');
18689                 Roo.log(component);
18690             }
18691             
18692         }
18693         
18694     },
18695     
18696         
18697         /**
18698          * Event Object.
18699          *
18700          *
18701          */
18702         event: false, 
18703     /**
18704          * wrapper for event.on - aliased later..  
18705          * Typically use to register a event handler for register:
18706          *
18707          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18708          *
18709          */
18710     on : false
18711    
18712     
18713     
18714 });
18715
18716 Roo.XComponent.event = new Roo.util.Observable({
18717                 events : { 
18718                         /**
18719                          * @event register
18720                          * Fires when an Component is registered,
18721                          * set the disable property on the Component to stop registration.
18722                          * @param {Roo.XComponent} c the component being registerd.
18723                          * 
18724                          */
18725                         'register' : true,
18726             /**
18727                          * @event beforebuild
18728                          * Fires before each Component is built
18729                          * can be used to apply permissions.
18730                          * @param {Roo.XComponent} c the component being registerd.
18731                          * 
18732                          */
18733                         'beforebuild' : true,
18734                         /**
18735                          * @event buildcomplete
18736                          * Fires on the top level element when all elements have been built
18737                          * @param {Roo.XComponent} the top level component.
18738                          */
18739                         'buildcomplete' : true
18740                         
18741                 }
18742 });
18743
18744 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18745  //
18746  /**
18747  * marked - a markdown parser
18748  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18749  * https://github.com/chjj/marked
18750  */
18751
18752
18753 /**
18754  *
18755  * Roo.Markdown - is a very crude wrapper around marked..
18756  *
18757  * usage:
18758  * 
18759  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18760  * 
18761  * Note: move the sample code to the bottom of this
18762  * file before uncommenting it.
18763  *
18764  */
18765
18766 Roo.Markdown = {};
18767 Roo.Markdown.toHtml = function(text) {
18768     
18769     var c = new Roo.Markdown.marked.setOptions({
18770             renderer: new Roo.Markdown.marked.Renderer(),
18771             gfm: true,
18772             tables: true,
18773             breaks: false,
18774             pedantic: false,
18775             sanitize: false,
18776             smartLists: true,
18777             smartypants: false
18778           });
18779     // A FEW HACKS!!?
18780     
18781     text = text.replace(/\\\n/g,' ');
18782     return Roo.Markdown.marked(text);
18783 };
18784 //
18785 // converter
18786 //
18787 // Wraps all "globals" so that the only thing
18788 // exposed is makeHtml().
18789 //
18790 (function() {
18791     
18792      /**
18793          * eval:var:escape
18794          * eval:var:unescape
18795          * eval:var:replace
18796          */
18797       
18798     /**
18799      * Helpers
18800      */
18801     
18802     var escape = function (html, encode) {
18803       return html
18804         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18805         .replace(/</g, '&lt;')
18806         .replace(/>/g, '&gt;')
18807         .replace(/"/g, '&quot;')
18808         .replace(/'/g, '&#39;');
18809     }
18810     
18811     var unescape = function (html) {
18812         // explicitly match decimal, hex, and named HTML entities 
18813       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18814         n = n.toLowerCase();
18815         if (n === 'colon') { return ':'; }
18816         if (n.charAt(0) === '#') {
18817           return n.charAt(1) === 'x'
18818             ? String.fromCharCode(parseInt(n.substring(2), 16))
18819             : String.fromCharCode(+n.substring(1));
18820         }
18821         return '';
18822       });
18823     }
18824     
18825     var replace = function (regex, opt) {
18826       regex = regex.source;
18827       opt = opt || '';
18828       return function self(name, val) {
18829         if (!name) { return new RegExp(regex, opt); }
18830         val = val.source || val;
18831         val = val.replace(/(^|[^\[])\^/g, '$1');
18832         regex = regex.replace(name, val);
18833         return self;
18834       };
18835     }
18836
18837
18838          /**
18839          * eval:var:noop
18840     */
18841     var noop = function () {}
18842     noop.exec = noop;
18843     
18844          /**
18845          * eval:var:merge
18846     */
18847     var merge = function (obj) {
18848       var i = 1
18849         , target
18850         , key;
18851     
18852       for (; i < arguments.length; i++) {
18853         target = arguments[i];
18854         for (key in target) {
18855           if (Object.prototype.hasOwnProperty.call(target, key)) {
18856             obj[key] = target[key];
18857           }
18858         }
18859       }
18860     
18861       return obj;
18862     }
18863     
18864     
18865     /**
18866      * Block-Level Grammar
18867      */
18868     
18869     
18870     
18871     
18872     var block = {
18873       newline: /^\n+/,
18874       code: /^( {4}[^\n]+\n*)+/,
18875       fences: noop,
18876       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18877       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18878       nptable: noop,
18879       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18880       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18881       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18882       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18883       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18884       table: noop,
18885       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18886       text: /^[^\n]+/
18887     };
18888     
18889     block.bullet = /(?:[*+-]|\d+\.)/;
18890     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18891     block.item = replace(block.item, 'gm')
18892       (/bull/g, block.bullet)
18893       ();
18894     
18895     block.list = replace(block.list)
18896       (/bull/g, block.bullet)
18897       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18898       ('def', '\\n+(?=' + block.def.source + ')')
18899       ();
18900     
18901     block.blockquote = replace(block.blockquote)
18902       ('def', block.def)
18903       ();
18904     
18905     block._tag = '(?!(?:'
18906       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18907       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18908       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18909     
18910     block.html = replace(block.html)
18911       ('comment', /<!--[\s\S]*?-->/)
18912       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18913       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18914       (/tag/g, block._tag)
18915       ();
18916     
18917     block.paragraph = replace(block.paragraph)
18918       ('hr', block.hr)
18919       ('heading', block.heading)
18920       ('lheading', block.lheading)
18921       ('blockquote', block.blockquote)
18922       ('tag', '<' + block._tag)
18923       ('def', block.def)
18924       ();
18925     
18926     /**
18927      * Normal Block Grammar
18928      */
18929     
18930     block.normal = merge({}, block);
18931     
18932     /**
18933      * GFM Block Grammar
18934      */
18935     
18936     block.gfm = merge({}, block.normal, {
18937       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18938       paragraph: /^/,
18939       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18940     });
18941     
18942     block.gfm.paragraph = replace(block.paragraph)
18943       ('(?!', '(?!'
18944         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18945         + block.list.source.replace('\\1', '\\3') + '|')
18946       ();
18947     
18948     /**
18949      * GFM + Tables Block Grammar
18950      */
18951     
18952     block.tables = merge({}, block.gfm, {
18953       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18954       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18955     });
18956     
18957     /**
18958      * Block Lexer
18959      */
18960     
18961     var Lexer = function (options) {
18962       this.tokens = [];
18963       this.tokens.links = {};
18964       this.options = options || marked.defaults;
18965       this.rules = block.normal;
18966     
18967       if (this.options.gfm) {
18968         if (this.options.tables) {
18969           this.rules = block.tables;
18970         } else {
18971           this.rules = block.gfm;
18972         }
18973       }
18974     }
18975     
18976     /**
18977      * Expose Block Rules
18978      */
18979     
18980     Lexer.rules = block;
18981     
18982     /**
18983      * Static Lex Method
18984      */
18985     
18986     Lexer.lex = function(src, options) {
18987       var lexer = new Lexer(options);
18988       return lexer.lex(src);
18989     };
18990     
18991     /**
18992      * Preprocessing
18993      */
18994     
18995     Lexer.prototype.lex = function(src) {
18996       src = src
18997         .replace(/\r\n|\r/g, '\n')
18998         .replace(/\t/g, '    ')
18999         .replace(/\u00a0/g, ' ')
19000         .replace(/\u2424/g, '\n');
19001     
19002       return this.token(src, true);
19003     };
19004     
19005     /**
19006      * Lexing
19007      */
19008     
19009     Lexer.prototype.token = function(src, top, bq) {
19010       var src = src.replace(/^ +$/gm, '')
19011         , next
19012         , loose
19013         , cap
19014         , bull
19015         , b
19016         , item
19017         , space
19018         , i
19019         , l;
19020     
19021       while (src) {
19022         // newline
19023         if (cap = this.rules.newline.exec(src)) {
19024           src = src.substring(cap[0].length);
19025           if (cap[0].length > 1) {
19026             this.tokens.push({
19027               type: 'space'
19028             });
19029           }
19030         }
19031     
19032         // code
19033         if (cap = this.rules.code.exec(src)) {
19034           src = src.substring(cap[0].length);
19035           cap = cap[0].replace(/^ {4}/gm, '');
19036           this.tokens.push({
19037             type: 'code',
19038             text: !this.options.pedantic
19039               ? cap.replace(/\n+$/, '')
19040               : cap
19041           });
19042           continue;
19043         }
19044     
19045         // fences (gfm)
19046         if (cap = this.rules.fences.exec(src)) {
19047           src = src.substring(cap[0].length);
19048           this.tokens.push({
19049             type: 'code',
19050             lang: cap[2],
19051             text: cap[3] || ''
19052           });
19053           continue;
19054         }
19055     
19056         // heading
19057         if (cap = this.rules.heading.exec(src)) {
19058           src = src.substring(cap[0].length);
19059           this.tokens.push({
19060             type: 'heading',
19061             depth: cap[1].length,
19062             text: cap[2]
19063           });
19064           continue;
19065         }
19066     
19067         // table no leading pipe (gfm)
19068         if (top && (cap = this.rules.nptable.exec(src))) {
19069           src = src.substring(cap[0].length);
19070     
19071           item = {
19072             type: 'table',
19073             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19074             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19075             cells: cap[3].replace(/\n$/, '').split('\n')
19076           };
19077     
19078           for (i = 0; i < item.align.length; i++) {
19079             if (/^ *-+: *$/.test(item.align[i])) {
19080               item.align[i] = 'right';
19081             } else if (/^ *:-+: *$/.test(item.align[i])) {
19082               item.align[i] = 'center';
19083             } else if (/^ *:-+ *$/.test(item.align[i])) {
19084               item.align[i] = 'left';
19085             } else {
19086               item.align[i] = null;
19087             }
19088           }
19089     
19090           for (i = 0; i < item.cells.length; i++) {
19091             item.cells[i] = item.cells[i].split(/ *\| */);
19092           }
19093     
19094           this.tokens.push(item);
19095     
19096           continue;
19097         }
19098     
19099         // lheading
19100         if (cap = this.rules.lheading.exec(src)) {
19101           src = src.substring(cap[0].length);
19102           this.tokens.push({
19103             type: 'heading',
19104             depth: cap[2] === '=' ? 1 : 2,
19105             text: cap[1]
19106           });
19107           continue;
19108         }
19109     
19110         // hr
19111         if (cap = this.rules.hr.exec(src)) {
19112           src = src.substring(cap[0].length);
19113           this.tokens.push({
19114             type: 'hr'
19115           });
19116           continue;
19117         }
19118     
19119         // blockquote
19120         if (cap = this.rules.blockquote.exec(src)) {
19121           src = src.substring(cap[0].length);
19122     
19123           this.tokens.push({
19124             type: 'blockquote_start'
19125           });
19126     
19127           cap = cap[0].replace(/^ *> ?/gm, '');
19128     
19129           // Pass `top` to keep the current
19130           // "toplevel" state. This is exactly
19131           // how markdown.pl works.
19132           this.token(cap, top, true);
19133     
19134           this.tokens.push({
19135             type: 'blockquote_end'
19136           });
19137     
19138           continue;
19139         }
19140     
19141         // list
19142         if (cap = this.rules.list.exec(src)) {
19143           src = src.substring(cap[0].length);
19144           bull = cap[2];
19145     
19146           this.tokens.push({
19147             type: 'list_start',
19148             ordered: bull.length > 1
19149           });
19150     
19151           // Get each top-level item.
19152           cap = cap[0].match(this.rules.item);
19153     
19154           next = false;
19155           l = cap.length;
19156           i = 0;
19157     
19158           for (; i < l; i++) {
19159             item = cap[i];
19160     
19161             // Remove the list item's bullet
19162             // so it is seen as the next token.
19163             space = item.length;
19164             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19165     
19166             // Outdent whatever the
19167             // list item contains. Hacky.
19168             if (~item.indexOf('\n ')) {
19169               space -= item.length;
19170               item = !this.options.pedantic
19171                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19172                 : item.replace(/^ {1,4}/gm, '');
19173             }
19174     
19175             // Determine whether the next list item belongs here.
19176             // Backpedal if it does not belong in this list.
19177             if (this.options.smartLists && i !== l - 1) {
19178               b = block.bullet.exec(cap[i + 1])[0];
19179               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19180                 src = cap.slice(i + 1).join('\n') + src;
19181                 i = l - 1;
19182               }
19183             }
19184     
19185             // Determine whether item is loose or not.
19186             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19187             // for discount behavior.
19188             loose = next || /\n\n(?!\s*$)/.test(item);
19189             if (i !== l - 1) {
19190               next = item.charAt(item.length - 1) === '\n';
19191               if (!loose) { loose = next; }
19192             }
19193     
19194             this.tokens.push({
19195               type: loose
19196                 ? 'loose_item_start'
19197                 : 'list_item_start'
19198             });
19199     
19200             // Recurse.
19201             this.token(item, false, bq);
19202     
19203             this.tokens.push({
19204               type: 'list_item_end'
19205             });
19206           }
19207     
19208           this.tokens.push({
19209             type: 'list_end'
19210           });
19211     
19212           continue;
19213         }
19214     
19215         // html
19216         if (cap = this.rules.html.exec(src)) {
19217           src = src.substring(cap[0].length);
19218           this.tokens.push({
19219             type: this.options.sanitize
19220               ? 'paragraph'
19221               : 'html',
19222             pre: !this.options.sanitizer
19223               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19224             text: cap[0]
19225           });
19226           continue;
19227         }
19228     
19229         // def
19230         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19231           src = src.substring(cap[0].length);
19232           this.tokens.links[cap[1].toLowerCase()] = {
19233             href: cap[2],
19234             title: cap[3]
19235           };
19236           continue;
19237         }
19238     
19239         // table (gfm)
19240         if (top && (cap = this.rules.table.exec(src))) {
19241           src = src.substring(cap[0].length);
19242     
19243           item = {
19244             type: 'table',
19245             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19246             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19247             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19248           };
19249     
19250           for (i = 0; i < item.align.length; i++) {
19251             if (/^ *-+: *$/.test(item.align[i])) {
19252               item.align[i] = 'right';
19253             } else if (/^ *:-+: *$/.test(item.align[i])) {
19254               item.align[i] = 'center';
19255             } else if (/^ *:-+ *$/.test(item.align[i])) {
19256               item.align[i] = 'left';
19257             } else {
19258               item.align[i] = null;
19259             }
19260           }
19261     
19262           for (i = 0; i < item.cells.length; i++) {
19263             item.cells[i] = item.cells[i]
19264               .replace(/^ *\| *| *\| *$/g, '')
19265               .split(/ *\| */);
19266           }
19267     
19268           this.tokens.push(item);
19269     
19270           continue;
19271         }
19272     
19273         // top-level paragraph
19274         if (top && (cap = this.rules.paragraph.exec(src))) {
19275           src = src.substring(cap[0].length);
19276           this.tokens.push({
19277             type: 'paragraph',
19278             text: cap[1].charAt(cap[1].length - 1) === '\n'
19279               ? cap[1].slice(0, -1)
19280               : cap[1]
19281           });
19282           continue;
19283         }
19284     
19285         // text
19286         if (cap = this.rules.text.exec(src)) {
19287           // Top-level should never reach here.
19288           src = src.substring(cap[0].length);
19289           this.tokens.push({
19290             type: 'text',
19291             text: cap[0]
19292           });
19293           continue;
19294         }
19295     
19296         if (src) {
19297           throw new
19298             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19299         }
19300       }
19301     
19302       return this.tokens;
19303     };
19304     
19305     /**
19306      * Inline-Level Grammar
19307      */
19308     
19309     var inline = {
19310       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19311       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19312       url: noop,
19313       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19314       link: /^!?\[(inside)\]\(href\)/,
19315       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19316       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19317       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19318       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19319       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19320       br: /^ {2,}\n(?!\s*$)/,
19321       del: noop,
19322       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19323     };
19324     
19325     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19326     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19327     
19328     inline.link = replace(inline.link)
19329       ('inside', inline._inside)
19330       ('href', inline._href)
19331       ();
19332     
19333     inline.reflink = replace(inline.reflink)
19334       ('inside', inline._inside)
19335       ();
19336     
19337     /**
19338      * Normal Inline Grammar
19339      */
19340     
19341     inline.normal = merge({}, inline);
19342     
19343     /**
19344      * Pedantic Inline Grammar
19345      */
19346     
19347     inline.pedantic = merge({}, inline.normal, {
19348       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19349       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19350     });
19351     
19352     /**
19353      * GFM Inline Grammar
19354      */
19355     
19356     inline.gfm = merge({}, inline.normal, {
19357       escape: replace(inline.escape)('])', '~|])')(),
19358       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19359       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19360       text: replace(inline.text)
19361         (']|', '~]|')
19362         ('|', '|https?://|')
19363         ()
19364     });
19365     
19366     /**
19367      * GFM + Line Breaks Inline Grammar
19368      */
19369     
19370     inline.breaks = merge({}, inline.gfm, {
19371       br: replace(inline.br)('{2,}', '*')(),
19372       text: replace(inline.gfm.text)('{2,}', '*')()
19373     });
19374     
19375     /**
19376      * Inline Lexer & Compiler
19377      */
19378     
19379     var InlineLexer  = function (links, options) {
19380       this.options = options || marked.defaults;
19381       this.links = links;
19382       this.rules = inline.normal;
19383       this.renderer = this.options.renderer || new Renderer;
19384       this.renderer.options = this.options;
19385     
19386       if (!this.links) {
19387         throw new
19388           Error('Tokens array requires a `links` property.');
19389       }
19390     
19391       if (this.options.gfm) {
19392         if (this.options.breaks) {
19393           this.rules = inline.breaks;
19394         } else {
19395           this.rules = inline.gfm;
19396         }
19397       } else if (this.options.pedantic) {
19398         this.rules = inline.pedantic;
19399       }
19400     }
19401     
19402     /**
19403      * Expose Inline Rules
19404      */
19405     
19406     InlineLexer.rules = inline;
19407     
19408     /**
19409      * Static Lexing/Compiling Method
19410      */
19411     
19412     InlineLexer.output = function(src, links, options) {
19413       var inline = new InlineLexer(links, options);
19414       return inline.output(src);
19415     };
19416     
19417     /**
19418      * Lexing/Compiling
19419      */
19420     
19421     InlineLexer.prototype.output = function(src) {
19422       var out = ''
19423         , link
19424         , text
19425         , href
19426         , cap;
19427     
19428       while (src) {
19429         // escape
19430         if (cap = this.rules.escape.exec(src)) {
19431           src = src.substring(cap[0].length);
19432           out += cap[1];
19433           continue;
19434         }
19435     
19436         // autolink
19437         if (cap = this.rules.autolink.exec(src)) {
19438           src = src.substring(cap[0].length);
19439           if (cap[2] === '@') {
19440             text = cap[1].charAt(6) === ':'
19441               ? this.mangle(cap[1].substring(7))
19442               : this.mangle(cap[1]);
19443             href = this.mangle('mailto:') + text;
19444           } else {
19445             text = escape(cap[1]);
19446             href = text;
19447           }
19448           out += this.renderer.link(href, null, text);
19449           continue;
19450         }
19451     
19452         // url (gfm)
19453         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19454           src = src.substring(cap[0].length);
19455           text = escape(cap[1]);
19456           href = text;
19457           out += this.renderer.link(href, null, text);
19458           continue;
19459         }
19460     
19461         // tag
19462         if (cap = this.rules.tag.exec(src)) {
19463           if (!this.inLink && /^<a /i.test(cap[0])) {
19464             this.inLink = true;
19465           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19466             this.inLink = false;
19467           }
19468           src = src.substring(cap[0].length);
19469           out += this.options.sanitize
19470             ? this.options.sanitizer
19471               ? this.options.sanitizer(cap[0])
19472               : escape(cap[0])
19473             : cap[0];
19474           continue;
19475         }
19476     
19477         // link
19478         if (cap = this.rules.link.exec(src)) {
19479           src = src.substring(cap[0].length);
19480           this.inLink = true;
19481           out += this.outputLink(cap, {
19482             href: cap[2],
19483             title: cap[3]
19484           });
19485           this.inLink = false;
19486           continue;
19487         }
19488     
19489         // reflink, nolink
19490         if ((cap = this.rules.reflink.exec(src))
19491             || (cap = this.rules.nolink.exec(src))) {
19492           src = src.substring(cap[0].length);
19493           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19494           link = this.links[link.toLowerCase()];
19495           if (!link || !link.href) {
19496             out += cap[0].charAt(0);
19497             src = cap[0].substring(1) + src;
19498             continue;
19499           }
19500           this.inLink = true;
19501           out += this.outputLink(cap, link);
19502           this.inLink = false;
19503           continue;
19504         }
19505     
19506         // strong
19507         if (cap = this.rules.strong.exec(src)) {
19508           src = src.substring(cap[0].length);
19509           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19510           continue;
19511         }
19512     
19513         // em
19514         if (cap = this.rules.em.exec(src)) {
19515           src = src.substring(cap[0].length);
19516           out += this.renderer.em(this.output(cap[2] || cap[1]));
19517           continue;
19518         }
19519     
19520         // code
19521         if (cap = this.rules.code.exec(src)) {
19522           src = src.substring(cap[0].length);
19523           out += this.renderer.codespan(escape(cap[2], true));
19524           continue;
19525         }
19526     
19527         // br
19528         if (cap = this.rules.br.exec(src)) {
19529           src = src.substring(cap[0].length);
19530           out += this.renderer.br();
19531           continue;
19532         }
19533     
19534         // del (gfm)
19535         if (cap = this.rules.del.exec(src)) {
19536           src = src.substring(cap[0].length);
19537           out += this.renderer.del(this.output(cap[1]));
19538           continue;
19539         }
19540     
19541         // text
19542         if (cap = this.rules.text.exec(src)) {
19543           src = src.substring(cap[0].length);
19544           out += this.renderer.text(escape(this.smartypants(cap[0])));
19545           continue;
19546         }
19547     
19548         if (src) {
19549           throw new
19550             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19551         }
19552       }
19553     
19554       return out;
19555     };
19556     
19557     /**
19558      * Compile Link
19559      */
19560     
19561     InlineLexer.prototype.outputLink = function(cap, link) {
19562       var href = escape(link.href)
19563         , title = link.title ? escape(link.title) : null;
19564     
19565       return cap[0].charAt(0) !== '!'
19566         ? this.renderer.link(href, title, this.output(cap[1]))
19567         : this.renderer.image(href, title, escape(cap[1]));
19568     };
19569     
19570     /**
19571      * Smartypants Transformations
19572      */
19573     
19574     InlineLexer.prototype.smartypants = function(text) {
19575       if (!this.options.smartypants)  { return text; }
19576       return text
19577         // em-dashes
19578         .replace(/---/g, '\u2014')
19579         // en-dashes
19580         .replace(/--/g, '\u2013')
19581         // opening singles
19582         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19583         // closing singles & apostrophes
19584         .replace(/'/g, '\u2019')
19585         // opening doubles
19586         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19587         // closing doubles
19588         .replace(/"/g, '\u201d')
19589         // ellipses
19590         .replace(/\.{3}/g, '\u2026');
19591     };
19592     
19593     /**
19594      * Mangle Links
19595      */
19596     
19597     InlineLexer.prototype.mangle = function(text) {
19598       if (!this.options.mangle) { return text; }
19599       var out = ''
19600         , l = text.length
19601         , i = 0
19602         , ch;
19603     
19604       for (; i < l; i++) {
19605         ch = text.charCodeAt(i);
19606         if (Math.random() > 0.5) {
19607           ch = 'x' + ch.toString(16);
19608         }
19609         out += '&#' + ch + ';';
19610       }
19611     
19612       return out;
19613     };
19614     
19615     /**
19616      * Renderer
19617      */
19618     
19619      /**
19620          * eval:var:Renderer
19621     */
19622     
19623     var Renderer   = function (options) {
19624       this.options = options || {};
19625     }
19626     
19627     Renderer.prototype.code = function(code, lang, escaped) {
19628       if (this.options.highlight) {
19629         var out = this.options.highlight(code, lang);
19630         if (out != null && out !== code) {
19631           escaped = true;
19632           code = out;
19633         }
19634       } else {
19635             // hack!!! - it's already escapeD?
19636             escaped = true;
19637       }
19638     
19639       if (!lang) {
19640         return '<pre><code>'
19641           + (escaped ? code : escape(code, true))
19642           + '\n</code></pre>';
19643       }
19644     
19645       return '<pre><code class="'
19646         + this.options.langPrefix
19647         + escape(lang, true)
19648         + '">'
19649         + (escaped ? code : escape(code, true))
19650         + '\n</code></pre>\n';
19651     };
19652     
19653     Renderer.prototype.blockquote = function(quote) {
19654       return '<blockquote>\n' + quote + '</blockquote>\n';
19655     };
19656     
19657     Renderer.prototype.html = function(html) {
19658       return html;
19659     };
19660     
19661     Renderer.prototype.heading = function(text, level, raw) {
19662       return '<h'
19663         + level
19664         + ' id="'
19665         + this.options.headerPrefix
19666         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19667         + '">'
19668         + text
19669         + '</h'
19670         + level
19671         + '>\n';
19672     };
19673     
19674     Renderer.prototype.hr = function() {
19675       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19676     };
19677     
19678     Renderer.prototype.list = function(body, ordered) {
19679       var type = ordered ? 'ol' : 'ul';
19680       return '<' + type + '>\n' + body + '</' + type + '>\n';
19681     };
19682     
19683     Renderer.prototype.listitem = function(text) {
19684       return '<li>' + text + '</li>\n';
19685     };
19686     
19687     Renderer.prototype.paragraph = function(text) {
19688       return '<p>' + text + '</p>\n';
19689     };
19690     
19691     Renderer.prototype.table = function(header, body) {
19692       return '<table class="table table-striped">\n'
19693         + '<thead>\n'
19694         + header
19695         + '</thead>\n'
19696         + '<tbody>\n'
19697         + body
19698         + '</tbody>\n'
19699         + '</table>\n';
19700     };
19701     
19702     Renderer.prototype.tablerow = function(content) {
19703       return '<tr>\n' + content + '</tr>\n';
19704     };
19705     
19706     Renderer.prototype.tablecell = function(content, flags) {
19707       var type = flags.header ? 'th' : 'td';
19708       var tag = flags.align
19709         ? '<' + type + ' style="text-align:' + flags.align + '">'
19710         : '<' + type + '>';
19711       return tag + content + '</' + type + '>\n';
19712     };
19713     
19714     // span level renderer
19715     Renderer.prototype.strong = function(text) {
19716       return '<strong>' + text + '</strong>';
19717     };
19718     
19719     Renderer.prototype.em = function(text) {
19720       return '<em>' + text + '</em>';
19721     };
19722     
19723     Renderer.prototype.codespan = function(text) {
19724       return '<code>' + text + '</code>';
19725     };
19726     
19727     Renderer.prototype.br = function() {
19728       return this.options.xhtml ? '<br/>' : '<br>';
19729     };
19730     
19731     Renderer.prototype.del = function(text) {
19732       return '<del>' + text + '</del>';
19733     };
19734     
19735     Renderer.prototype.link = function(href, title, text) {
19736       if (this.options.sanitize) {
19737         try {
19738           var prot = decodeURIComponent(unescape(href))
19739             .replace(/[^\w:]/g, '')
19740             .toLowerCase();
19741         } catch (e) {
19742           return '';
19743         }
19744         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19745           return '';
19746         }
19747       }
19748       var out = '<a href="' + href + '"';
19749       if (title) {
19750         out += ' title="' + title + '"';
19751       }
19752       out += '>' + text + '</a>';
19753       return out;
19754     };
19755     
19756     Renderer.prototype.image = function(href, title, text) {
19757       var out = '<img src="' + href + '" alt="' + text + '"';
19758       if (title) {
19759         out += ' title="' + title + '"';
19760       }
19761       out += this.options.xhtml ? '/>' : '>';
19762       return out;
19763     };
19764     
19765     Renderer.prototype.text = function(text) {
19766       return text;
19767     };
19768     
19769     /**
19770      * Parsing & Compiling
19771      */
19772          /**
19773          * eval:var:Parser
19774     */
19775     
19776     var Parser= function (options) {
19777       this.tokens = [];
19778       this.token = null;
19779       this.options = options || marked.defaults;
19780       this.options.renderer = this.options.renderer || new Renderer;
19781       this.renderer = this.options.renderer;
19782       this.renderer.options = this.options;
19783     }
19784     
19785     /**
19786      * Static Parse Method
19787      */
19788     
19789     Parser.parse = function(src, options, renderer) {
19790       var parser = new Parser(options, renderer);
19791       return parser.parse(src);
19792     };
19793     
19794     /**
19795      * Parse Loop
19796      */
19797     
19798     Parser.prototype.parse = function(src) {
19799       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19800       this.tokens = src.reverse();
19801     
19802       var out = '';
19803       while (this.next()) {
19804         out += this.tok();
19805       }
19806     
19807       return out;
19808     };
19809     
19810     /**
19811      * Next Token
19812      */
19813     
19814     Parser.prototype.next = function() {
19815       return this.token = this.tokens.pop();
19816     };
19817     
19818     /**
19819      * Preview Next Token
19820      */
19821     
19822     Parser.prototype.peek = function() {
19823       return this.tokens[this.tokens.length - 1] || 0;
19824     };
19825     
19826     /**
19827      * Parse Text Tokens
19828      */
19829     
19830     Parser.prototype.parseText = function() {
19831       var body = this.token.text;
19832     
19833       while (this.peek().type === 'text') {
19834         body += '\n' + this.next().text;
19835       }
19836     
19837       return this.inline.output(body);
19838     };
19839     
19840     /**
19841      * Parse Current Token
19842      */
19843     
19844     Parser.prototype.tok = function() {
19845       switch (this.token.type) {
19846         case 'space': {
19847           return '';
19848         }
19849         case 'hr': {
19850           return this.renderer.hr();
19851         }
19852         case 'heading': {
19853           return this.renderer.heading(
19854             this.inline.output(this.token.text),
19855             this.token.depth,
19856             this.token.text);
19857         }
19858         case 'code': {
19859           return this.renderer.code(this.token.text,
19860             this.token.lang,
19861             this.token.escaped);
19862         }
19863         case 'table': {
19864           var header = ''
19865             , body = ''
19866             , i
19867             , row
19868             , cell
19869             , flags
19870             , j;
19871     
19872           // header
19873           cell = '';
19874           for (i = 0; i < this.token.header.length; i++) {
19875             flags = { header: true, align: this.token.align[i] };
19876             cell += this.renderer.tablecell(
19877               this.inline.output(this.token.header[i]),
19878               { header: true, align: this.token.align[i] }
19879             );
19880           }
19881           header += this.renderer.tablerow(cell);
19882     
19883           for (i = 0; i < this.token.cells.length; i++) {
19884             row = this.token.cells[i];
19885     
19886             cell = '';
19887             for (j = 0; j < row.length; j++) {
19888               cell += this.renderer.tablecell(
19889                 this.inline.output(row[j]),
19890                 { header: false, align: this.token.align[j] }
19891               );
19892             }
19893     
19894             body += this.renderer.tablerow(cell);
19895           }
19896           return this.renderer.table(header, body);
19897         }
19898         case 'blockquote_start': {
19899           var body = '';
19900     
19901           while (this.next().type !== 'blockquote_end') {
19902             body += this.tok();
19903           }
19904     
19905           return this.renderer.blockquote(body);
19906         }
19907         case 'list_start': {
19908           var body = ''
19909             , ordered = this.token.ordered;
19910     
19911           while (this.next().type !== 'list_end') {
19912             body += this.tok();
19913           }
19914     
19915           return this.renderer.list(body, ordered);
19916         }
19917         case 'list_item_start': {
19918           var body = '';
19919     
19920           while (this.next().type !== 'list_item_end') {
19921             body += this.token.type === 'text'
19922               ? this.parseText()
19923               : this.tok();
19924           }
19925     
19926           return this.renderer.listitem(body);
19927         }
19928         case 'loose_item_start': {
19929           var body = '';
19930     
19931           while (this.next().type !== 'list_item_end') {
19932             body += this.tok();
19933           }
19934     
19935           return this.renderer.listitem(body);
19936         }
19937         case 'html': {
19938           var html = !this.token.pre && !this.options.pedantic
19939             ? this.inline.output(this.token.text)
19940             : this.token.text;
19941           return this.renderer.html(html);
19942         }
19943         case 'paragraph': {
19944           return this.renderer.paragraph(this.inline.output(this.token.text));
19945         }
19946         case 'text': {
19947           return this.renderer.paragraph(this.parseText());
19948         }
19949       }
19950     };
19951   
19952     
19953     /**
19954      * Marked
19955      */
19956          /**
19957          * eval:var:marked
19958     */
19959     var marked = function (src, opt, callback) {
19960       if (callback || typeof opt === 'function') {
19961         if (!callback) {
19962           callback = opt;
19963           opt = null;
19964         }
19965     
19966         opt = merge({}, marked.defaults, opt || {});
19967     
19968         var highlight = opt.highlight
19969           , tokens
19970           , pending
19971           , i = 0;
19972     
19973         try {
19974           tokens = Lexer.lex(src, opt)
19975         } catch (e) {
19976           return callback(e);
19977         }
19978     
19979         pending = tokens.length;
19980          /**
19981          * eval:var:done
19982     */
19983         var done = function(err) {
19984           if (err) {
19985             opt.highlight = highlight;
19986             return callback(err);
19987           }
19988     
19989           var out;
19990     
19991           try {
19992             out = Parser.parse(tokens, opt);
19993           } catch (e) {
19994             err = e;
19995           }
19996     
19997           opt.highlight = highlight;
19998     
19999           return err
20000             ? callback(err)
20001             : callback(null, out);
20002         };
20003     
20004         if (!highlight || highlight.length < 3) {
20005           return done();
20006         }
20007     
20008         delete opt.highlight;
20009     
20010         if (!pending) { return done(); }
20011     
20012         for (; i < tokens.length; i++) {
20013           (function(token) {
20014             if (token.type !== 'code') {
20015               return --pending || done();
20016             }
20017             return highlight(token.text, token.lang, function(err, code) {
20018               if (err) { return done(err); }
20019               if (code == null || code === token.text) {
20020                 return --pending || done();
20021               }
20022               token.text = code;
20023               token.escaped = true;
20024               --pending || done();
20025             });
20026           })(tokens[i]);
20027         }
20028     
20029         return;
20030       }
20031       try {
20032         if (opt) { opt = merge({}, marked.defaults, opt); }
20033         return Parser.parse(Lexer.lex(src, opt), opt);
20034       } catch (e) {
20035         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20036         if ((opt || marked.defaults).silent) {
20037           return '<p>An error occured:</p><pre>'
20038             + escape(e.message + '', true)
20039             + '</pre>';
20040         }
20041         throw e;
20042       }
20043     }
20044     
20045     /**
20046      * Options
20047      */
20048     
20049     marked.options =
20050     marked.setOptions = function(opt) {
20051       merge(marked.defaults, opt);
20052       return marked;
20053     };
20054     
20055     marked.defaults = {
20056       gfm: true,
20057       tables: true,
20058       breaks: false,
20059       pedantic: false,
20060       sanitize: false,
20061       sanitizer: null,
20062       mangle: true,
20063       smartLists: false,
20064       silent: false,
20065       highlight: null,
20066       langPrefix: 'lang-',
20067       smartypants: false,
20068       headerPrefix: '',
20069       renderer: new Renderer,
20070       xhtml: false
20071     };
20072     
20073     /**
20074      * Expose
20075      */
20076     
20077     marked.Parser = Parser;
20078     marked.parser = Parser.parse;
20079     
20080     marked.Renderer = Renderer;
20081     
20082     marked.Lexer = Lexer;
20083     marked.lexer = Lexer.lex;
20084     
20085     marked.InlineLexer = InlineLexer;
20086     marked.inlineLexer = InlineLexer.output;
20087     
20088     marked.parse = marked;
20089     
20090     Roo.Markdown.marked = marked;
20091
20092 })();/*
20093  * Based on:
20094  * Ext JS Library 1.1.1
20095  * Copyright(c) 2006-2007, Ext JS, LLC.
20096  *
20097  * Originally Released Under LGPL - original licence link has changed is not relivant.
20098  *
20099  * Fork - LGPL
20100  * <script type="text/javascript">
20101  */
20102
20103
20104
20105 /*
20106  * These classes are derivatives of the similarly named classes in the YUI Library.
20107  * The original license:
20108  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20109  * Code licensed under the BSD License:
20110  * http://developer.yahoo.net/yui/license.txt
20111  */
20112
20113 (function() {
20114
20115 var Event=Roo.EventManager;
20116 var Dom=Roo.lib.Dom;
20117
20118 /**
20119  * @class Roo.dd.DragDrop
20120  * @extends Roo.util.Observable
20121  * Defines the interface and base operation of items that that can be
20122  * dragged or can be drop targets.  It was designed to be extended, overriding
20123  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20124  * Up to three html elements can be associated with a DragDrop instance:
20125  * <ul>
20126  * <li>linked element: the element that is passed into the constructor.
20127  * This is the element which defines the boundaries for interaction with
20128  * other DragDrop objects.</li>
20129  * <li>handle element(s): The drag operation only occurs if the element that
20130  * was clicked matches a handle element.  By default this is the linked
20131  * element, but there are times that you will want only a portion of the
20132  * linked element to initiate the drag operation, and the setHandleElId()
20133  * method provides a way to define this.</li>
20134  * <li>drag element: this represents the element that would be moved along
20135  * with the cursor during a drag operation.  By default, this is the linked
20136  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20137  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20138  * </li>
20139  * </ul>
20140  * This class should not be instantiated until the onload event to ensure that
20141  * the associated elements are available.
20142  * The following would define a DragDrop obj that would interact with any
20143  * other DragDrop obj in the "group1" group:
20144  * <pre>
20145  *  dd = new Roo.dd.DragDrop("div1", "group1");
20146  * </pre>
20147  * Since none of the event handlers have been implemented, nothing would
20148  * actually happen if you were to run the code above.  Normally you would
20149  * override this class or one of the default implementations, but you can
20150  * also override the methods you want on an instance of the class...
20151  * <pre>
20152  *  dd.onDragDrop = function(e, id) {
20153  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20154  *  }
20155  * </pre>
20156  * @constructor
20157  * @param {String} id of the element that is linked to this instance
20158  * @param {String} sGroup the group of related DragDrop objects
20159  * @param {object} config an object containing configurable attributes
20160  *                Valid properties for DragDrop:
20161  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20162  */
20163 Roo.dd.DragDrop = function(id, sGroup, config) {
20164     if (id) {
20165         this.init(id, sGroup, config);
20166     }
20167     
20168 };
20169
20170 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20171
20172     /**
20173      * The id of the element associated with this object.  This is what we
20174      * refer to as the "linked element" because the size and position of
20175      * this element is used to determine when the drag and drop objects have
20176      * interacted.
20177      * @property id
20178      * @type String
20179      */
20180     id: null,
20181
20182     /**
20183      * Configuration attributes passed into the constructor
20184      * @property config
20185      * @type object
20186      */
20187     config: null,
20188
20189     /**
20190      * The id of the element that will be dragged.  By default this is same
20191      * as the linked element , but could be changed to another element. Ex:
20192      * Roo.dd.DDProxy
20193      * @property dragElId
20194      * @type String
20195      * @private
20196      */
20197     dragElId: null,
20198
20199     /**
20200      * the id of the element that initiates the drag operation.  By default
20201      * this is the linked element, but could be changed to be a child of this
20202      * element.  This lets us do things like only starting the drag when the
20203      * header element within the linked html element is clicked.
20204      * @property handleElId
20205      * @type String
20206      * @private
20207      */
20208     handleElId: null,
20209
20210     /**
20211      * An associative array of HTML tags that will be ignored if clicked.
20212      * @property invalidHandleTypes
20213      * @type {string: string}
20214      */
20215     invalidHandleTypes: null,
20216
20217     /**
20218      * An associative array of ids for elements that will be ignored if clicked
20219      * @property invalidHandleIds
20220      * @type {string: string}
20221      */
20222     invalidHandleIds: null,
20223
20224     /**
20225      * An indexted array of css class names for elements that will be ignored
20226      * if clicked.
20227      * @property invalidHandleClasses
20228      * @type string[]
20229      */
20230     invalidHandleClasses: null,
20231
20232     /**
20233      * The linked element's absolute X position at the time the drag was
20234      * started
20235      * @property startPageX
20236      * @type int
20237      * @private
20238      */
20239     startPageX: 0,
20240
20241     /**
20242      * The linked element's absolute X position at the time the drag was
20243      * started
20244      * @property startPageY
20245      * @type int
20246      * @private
20247      */
20248     startPageY: 0,
20249
20250     /**
20251      * The group defines a logical collection of DragDrop objects that are
20252      * related.  Instances only get events when interacting with other
20253      * DragDrop object in the same group.  This lets us define multiple
20254      * groups using a single DragDrop subclass if we want.
20255      * @property groups
20256      * @type {string: string}
20257      */
20258     groups: null,
20259
20260     /**
20261      * Individual drag/drop instances can be locked.  This will prevent
20262      * onmousedown start drag.
20263      * @property locked
20264      * @type boolean
20265      * @private
20266      */
20267     locked: false,
20268
20269     /**
20270      * Lock this instance
20271      * @method lock
20272      */
20273     lock: function() { this.locked = true; },
20274
20275     /**
20276      * Unlock this instace
20277      * @method unlock
20278      */
20279     unlock: function() { this.locked = false; },
20280
20281     /**
20282      * By default, all insances can be a drop target.  This can be disabled by
20283      * setting isTarget to false.
20284      * @method isTarget
20285      * @type boolean
20286      */
20287     isTarget: true,
20288
20289     /**
20290      * The padding configured for this drag and drop object for calculating
20291      * the drop zone intersection with this object.
20292      * @method padding
20293      * @type int[]
20294      */
20295     padding: null,
20296
20297     /**
20298      * Cached reference to the linked element
20299      * @property _domRef
20300      * @private
20301      */
20302     _domRef: null,
20303
20304     /**
20305      * Internal typeof flag
20306      * @property __ygDragDrop
20307      * @private
20308      */
20309     __ygDragDrop: true,
20310
20311     /**
20312      * Set to true when horizontal contraints are applied
20313      * @property constrainX
20314      * @type boolean
20315      * @private
20316      */
20317     constrainX: false,
20318
20319     /**
20320      * Set to true when vertical contraints are applied
20321      * @property constrainY
20322      * @type boolean
20323      * @private
20324      */
20325     constrainY: false,
20326
20327     /**
20328      * The left constraint
20329      * @property minX
20330      * @type int
20331      * @private
20332      */
20333     minX: 0,
20334
20335     /**
20336      * The right constraint
20337      * @property maxX
20338      * @type int
20339      * @private
20340      */
20341     maxX: 0,
20342
20343     /**
20344      * The up constraint
20345      * @property minY
20346      * @type int
20347      * @type int
20348      * @private
20349      */
20350     minY: 0,
20351
20352     /**
20353      * The down constraint
20354      * @property maxY
20355      * @type int
20356      * @private
20357      */
20358     maxY: 0,
20359
20360     /**
20361      * Maintain offsets when we resetconstraints.  Set to true when you want
20362      * the position of the element relative to its parent to stay the same
20363      * when the page changes
20364      *
20365      * @property maintainOffset
20366      * @type boolean
20367      */
20368     maintainOffset: false,
20369
20370     /**
20371      * Array of pixel locations the element will snap to if we specified a
20372      * horizontal graduation/interval.  This array is generated automatically
20373      * when you define a tick interval.
20374      * @property xTicks
20375      * @type int[]
20376      */
20377     xTicks: null,
20378
20379     /**
20380      * Array of pixel locations the element will snap to if we specified a
20381      * vertical graduation/interval.  This array is generated automatically
20382      * when you define a tick interval.
20383      * @property yTicks
20384      * @type int[]
20385      */
20386     yTicks: null,
20387
20388     /**
20389      * By default the drag and drop instance will only respond to the primary
20390      * button click (left button for a right-handed mouse).  Set to true to
20391      * allow drag and drop to start with any mouse click that is propogated
20392      * by the browser
20393      * @property primaryButtonOnly
20394      * @type boolean
20395      */
20396     primaryButtonOnly: true,
20397
20398     /**
20399      * The availabe property is false until the linked dom element is accessible.
20400      * @property available
20401      * @type boolean
20402      */
20403     available: false,
20404
20405     /**
20406      * By default, drags can only be initiated if the mousedown occurs in the
20407      * region the linked element is.  This is done in part to work around a
20408      * bug in some browsers that mis-report the mousedown if the previous
20409      * mouseup happened outside of the window.  This property is set to true
20410      * if outer handles are defined.
20411      *
20412      * @property hasOuterHandles
20413      * @type boolean
20414      * @default false
20415      */
20416     hasOuterHandles: false,
20417
20418     /**
20419      * Code that executes immediately before the startDrag event
20420      * @method b4StartDrag
20421      * @private
20422      */
20423     b4StartDrag: function(x, y) { },
20424
20425     /**
20426      * Abstract method called after a drag/drop object is clicked
20427      * and the drag or mousedown time thresholds have beeen met.
20428      * @method startDrag
20429      * @param {int} X click location
20430      * @param {int} Y click location
20431      */
20432     startDrag: function(x, y) { /* override this */ },
20433
20434     /**
20435      * Code that executes immediately before the onDrag event
20436      * @method b4Drag
20437      * @private
20438      */
20439     b4Drag: function(e) { },
20440
20441     /**
20442      * Abstract method called during the onMouseMove event while dragging an
20443      * object.
20444      * @method onDrag
20445      * @param {Event} e the mousemove event
20446      */
20447     onDrag: function(e) { /* override this */ },
20448
20449     /**
20450      * Abstract method called when this element fist begins hovering over
20451      * another DragDrop obj
20452      * @method onDragEnter
20453      * @param {Event} e the mousemove event
20454      * @param {String|DragDrop[]} id In POINT mode, the element
20455      * id this is hovering over.  In INTERSECT mode, an array of one or more
20456      * dragdrop items being hovered over.
20457      */
20458     onDragEnter: function(e, id) { /* override this */ },
20459
20460     /**
20461      * Code that executes immediately before the onDragOver event
20462      * @method b4DragOver
20463      * @private
20464      */
20465     b4DragOver: function(e) { },
20466
20467     /**
20468      * Abstract method called when this element is hovering over another
20469      * DragDrop obj
20470      * @method onDragOver
20471      * @param {Event} e the mousemove event
20472      * @param {String|DragDrop[]} id In POINT mode, the element
20473      * id this is hovering over.  In INTERSECT mode, an array of dd items
20474      * being hovered over.
20475      */
20476     onDragOver: function(e, id) { /* override this */ },
20477
20478     /**
20479      * Code that executes immediately before the onDragOut event
20480      * @method b4DragOut
20481      * @private
20482      */
20483     b4DragOut: function(e) { },
20484
20485     /**
20486      * Abstract method called when we are no longer hovering over an element
20487      * @method onDragOut
20488      * @param {Event} e the mousemove event
20489      * @param {String|DragDrop[]} id In POINT mode, the element
20490      * id this was hovering over.  In INTERSECT mode, an array of dd items
20491      * that the mouse is no longer over.
20492      */
20493     onDragOut: function(e, id) { /* override this */ },
20494
20495     /**
20496      * Code that executes immediately before the onDragDrop event
20497      * @method b4DragDrop
20498      * @private
20499      */
20500     b4DragDrop: function(e) { },
20501
20502     /**
20503      * Abstract method called when this item is dropped on another DragDrop
20504      * obj
20505      * @method onDragDrop
20506      * @param {Event} e the mouseup event
20507      * @param {String|DragDrop[]} id In POINT mode, the element
20508      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20509      * was dropped on.
20510      */
20511     onDragDrop: function(e, id) { /* override this */ },
20512
20513     /**
20514      * Abstract method called when this item is dropped on an area with no
20515      * drop target
20516      * @method onInvalidDrop
20517      * @param {Event} e the mouseup event
20518      */
20519     onInvalidDrop: function(e) { /* override this */ },
20520
20521     /**
20522      * Code that executes immediately before the endDrag event
20523      * @method b4EndDrag
20524      * @private
20525      */
20526     b4EndDrag: function(e) { },
20527
20528     /**
20529      * Fired when we are done dragging the object
20530      * @method endDrag
20531      * @param {Event} e the mouseup event
20532      */
20533     endDrag: function(e) { /* override this */ },
20534
20535     /**
20536      * Code executed immediately before the onMouseDown event
20537      * @method b4MouseDown
20538      * @param {Event} e the mousedown event
20539      * @private
20540      */
20541     b4MouseDown: function(e) {  },
20542
20543     /**
20544      * Event handler that fires when a drag/drop obj gets a mousedown
20545      * @method onMouseDown
20546      * @param {Event} e the mousedown event
20547      */
20548     onMouseDown: function(e) { /* override this */ },
20549
20550     /**
20551      * Event handler that fires when a drag/drop obj gets a mouseup
20552      * @method onMouseUp
20553      * @param {Event} e the mouseup event
20554      */
20555     onMouseUp: function(e) { /* override this */ },
20556
20557     /**
20558      * Override the onAvailable method to do what is needed after the initial
20559      * position was determined.
20560      * @method onAvailable
20561      */
20562     onAvailable: function () {
20563     },
20564
20565     /*
20566      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20567      * @type Object
20568      */
20569     defaultPadding : {left:0, right:0, top:0, bottom:0},
20570
20571     /*
20572      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20573  *
20574  * Usage:
20575  <pre><code>
20576  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20577                 { dragElId: "existingProxyDiv" });
20578  dd.startDrag = function(){
20579      this.constrainTo("parent-id");
20580  };
20581  </code></pre>
20582  * Or you can initalize it using the {@link Roo.Element} object:
20583  <pre><code>
20584  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20585      startDrag : function(){
20586          this.constrainTo("parent-id");
20587      }
20588  });
20589  </code></pre>
20590      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20591      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20592      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20593      * an object containing the sides to pad. For example: {right:10, bottom:10}
20594      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20595      */
20596     constrainTo : function(constrainTo, pad, inContent){
20597         if(typeof pad == "number"){
20598             pad = {left: pad, right:pad, top:pad, bottom:pad};
20599         }
20600         pad = pad || this.defaultPadding;
20601         var b = Roo.get(this.getEl()).getBox();
20602         var ce = Roo.get(constrainTo);
20603         var s = ce.getScroll();
20604         var c, cd = ce.dom;
20605         if(cd == document.body){
20606             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20607         }else{
20608             xy = ce.getXY();
20609             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20610         }
20611
20612
20613         var topSpace = b.y - c.y;
20614         var leftSpace = b.x - c.x;
20615
20616         this.resetConstraints();
20617         this.setXConstraint(leftSpace - (pad.left||0), // left
20618                 c.width - leftSpace - b.width - (pad.right||0) //right
20619         );
20620         this.setYConstraint(topSpace - (pad.top||0), //top
20621                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20622         );
20623     },
20624
20625     /**
20626      * Returns a reference to the linked element
20627      * @method getEl
20628      * @return {HTMLElement} the html element
20629      */
20630     getEl: function() {
20631         if (!this._domRef) {
20632             this._domRef = Roo.getDom(this.id);
20633         }
20634
20635         return this._domRef;
20636     },
20637
20638     /**
20639      * Returns a reference to the actual element to drag.  By default this is
20640      * the same as the html element, but it can be assigned to another
20641      * element. An example of this can be found in Roo.dd.DDProxy
20642      * @method getDragEl
20643      * @return {HTMLElement} the html element
20644      */
20645     getDragEl: function() {
20646         return Roo.getDom(this.dragElId);
20647     },
20648
20649     /**
20650      * Sets up the DragDrop object.  Must be called in the constructor of any
20651      * Roo.dd.DragDrop subclass
20652      * @method init
20653      * @param id the id of the linked element
20654      * @param {String} sGroup the group of related items
20655      * @param {object} config configuration attributes
20656      */
20657     init: function(id, sGroup, config) {
20658         this.initTarget(id, sGroup, config);
20659         if (!Roo.isTouch) {
20660             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20661         }
20662         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20663         // Event.on(this.id, "selectstart", Event.preventDefault);
20664     },
20665
20666     /**
20667      * Initializes Targeting functionality only... the object does not
20668      * get a mousedown handler.
20669      * @method initTarget
20670      * @param id the id of the linked element
20671      * @param {String} sGroup the group of related items
20672      * @param {object} config configuration attributes
20673      */
20674     initTarget: function(id, sGroup, config) {
20675
20676         // configuration attributes
20677         this.config = config || {};
20678
20679         // create a local reference to the drag and drop manager
20680         this.DDM = Roo.dd.DDM;
20681         // initialize the groups array
20682         this.groups = {};
20683
20684         // assume that we have an element reference instead of an id if the
20685         // parameter is not a string
20686         if (typeof id !== "string") {
20687             id = Roo.id(id);
20688         }
20689
20690         // set the id
20691         this.id = id;
20692
20693         // add to an interaction group
20694         this.addToGroup((sGroup) ? sGroup : "default");
20695
20696         // We don't want to register this as the handle with the manager
20697         // so we just set the id rather than calling the setter.
20698         this.handleElId = id;
20699
20700         // the linked element is the element that gets dragged by default
20701         this.setDragElId(id);
20702
20703         // by default, clicked anchors will not start drag operations.
20704         this.invalidHandleTypes = { A: "A" };
20705         this.invalidHandleIds = {};
20706         this.invalidHandleClasses = [];
20707
20708         this.applyConfig();
20709
20710         this.handleOnAvailable();
20711     },
20712
20713     /**
20714      * Applies the configuration parameters that were passed into the constructor.
20715      * This is supposed to happen at each level through the inheritance chain.  So
20716      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20717      * DragDrop in order to get all of the parameters that are available in
20718      * each object.
20719      * @method applyConfig
20720      */
20721     applyConfig: function() {
20722
20723         // configurable properties:
20724         //    padding, isTarget, maintainOffset, primaryButtonOnly
20725         this.padding           = this.config.padding || [0, 0, 0, 0];
20726         this.isTarget          = (this.config.isTarget !== false);
20727         this.maintainOffset    = (this.config.maintainOffset);
20728         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20729
20730     },
20731
20732     /**
20733      * Executed when the linked element is available
20734      * @method handleOnAvailable
20735      * @private
20736      */
20737     handleOnAvailable: function() {
20738         this.available = true;
20739         this.resetConstraints();
20740         this.onAvailable();
20741     },
20742
20743      /**
20744      * Configures the padding for the target zone in px.  Effectively expands
20745      * (or reduces) the virtual object size for targeting calculations.
20746      * Supports css-style shorthand; if only one parameter is passed, all sides
20747      * will have that padding, and if only two are passed, the top and bottom
20748      * will have the first param, the left and right the second.
20749      * @method setPadding
20750      * @param {int} iTop    Top pad
20751      * @param {int} iRight  Right pad
20752      * @param {int} iBot    Bot pad
20753      * @param {int} iLeft   Left pad
20754      */
20755     setPadding: function(iTop, iRight, iBot, iLeft) {
20756         // this.padding = [iLeft, iRight, iTop, iBot];
20757         if (!iRight && 0 !== iRight) {
20758             this.padding = [iTop, iTop, iTop, iTop];
20759         } else if (!iBot && 0 !== iBot) {
20760             this.padding = [iTop, iRight, iTop, iRight];
20761         } else {
20762             this.padding = [iTop, iRight, iBot, iLeft];
20763         }
20764     },
20765
20766     /**
20767      * Stores the initial placement of the linked element.
20768      * @method setInitialPosition
20769      * @param {int} diffX   the X offset, default 0
20770      * @param {int} diffY   the Y offset, default 0
20771      */
20772     setInitPosition: function(diffX, diffY) {
20773         var el = this.getEl();
20774
20775         if (!this.DDM.verifyEl(el)) {
20776             return;
20777         }
20778
20779         var dx = diffX || 0;
20780         var dy = diffY || 0;
20781
20782         var p = Dom.getXY( el );
20783
20784         this.initPageX = p[0] - dx;
20785         this.initPageY = p[1] - dy;
20786
20787         this.lastPageX = p[0];
20788         this.lastPageY = p[1];
20789
20790
20791         this.setStartPosition(p);
20792     },
20793
20794     /**
20795      * Sets the start position of the element.  This is set when the obj
20796      * is initialized, the reset when a drag is started.
20797      * @method setStartPosition
20798      * @param pos current position (from previous lookup)
20799      * @private
20800      */
20801     setStartPosition: function(pos) {
20802         var p = pos || Dom.getXY( this.getEl() );
20803         this.deltaSetXY = null;
20804
20805         this.startPageX = p[0];
20806         this.startPageY = p[1];
20807     },
20808
20809     /**
20810      * Add this instance to a group of related drag/drop objects.  All
20811      * instances belong to at least one group, and can belong to as many
20812      * groups as needed.
20813      * @method addToGroup
20814      * @param sGroup {string} the name of the group
20815      */
20816     addToGroup: function(sGroup) {
20817         this.groups[sGroup] = true;
20818         this.DDM.regDragDrop(this, sGroup);
20819     },
20820
20821     /**
20822      * Remove's this instance from the supplied interaction group
20823      * @method removeFromGroup
20824      * @param {string}  sGroup  The group to drop
20825      */
20826     removeFromGroup: function(sGroup) {
20827         if (this.groups[sGroup]) {
20828             delete this.groups[sGroup];
20829         }
20830
20831         this.DDM.removeDDFromGroup(this, sGroup);
20832     },
20833
20834     /**
20835      * Allows you to specify that an element other than the linked element
20836      * will be moved with the cursor during a drag
20837      * @method setDragElId
20838      * @param id {string} the id of the element that will be used to initiate the drag
20839      */
20840     setDragElId: function(id) {
20841         this.dragElId = id;
20842     },
20843
20844     /**
20845      * Allows you to specify a child of the linked element that should be
20846      * used to initiate the drag operation.  An example of this would be if
20847      * you have a content div with text and links.  Clicking anywhere in the
20848      * content area would normally start the drag operation.  Use this method
20849      * to specify that an element inside of the content div is the element
20850      * that starts the drag operation.
20851      * @method setHandleElId
20852      * @param id {string} the id of the element that will be used to
20853      * initiate the drag.
20854      */
20855     setHandleElId: function(id) {
20856         if (typeof id !== "string") {
20857             id = Roo.id(id);
20858         }
20859         this.handleElId = id;
20860         this.DDM.regHandle(this.id, id);
20861     },
20862
20863     /**
20864      * Allows you to set an element outside of the linked element as a drag
20865      * handle
20866      * @method setOuterHandleElId
20867      * @param id the id of the element that will be used to initiate the drag
20868      */
20869     setOuterHandleElId: function(id) {
20870         if (typeof id !== "string") {
20871             id = Roo.id(id);
20872         }
20873         Event.on(id, "mousedown",
20874                 this.handleMouseDown, this);
20875         this.setHandleElId(id);
20876
20877         this.hasOuterHandles = true;
20878     },
20879
20880     /**
20881      * Remove all drag and drop hooks for this element
20882      * @method unreg
20883      */
20884     unreg: function() {
20885         Event.un(this.id, "mousedown",
20886                 this.handleMouseDown);
20887         Event.un(this.id, "touchstart",
20888                 this.handleMouseDown);
20889         this._domRef = null;
20890         this.DDM._remove(this);
20891     },
20892
20893     destroy : function(){
20894         this.unreg();
20895     },
20896
20897     /**
20898      * Returns true if this instance is locked, or the drag drop mgr is locked
20899      * (meaning that all drag/drop is disabled on the page.)
20900      * @method isLocked
20901      * @return {boolean} true if this obj or all drag/drop is locked, else
20902      * false
20903      */
20904     isLocked: function() {
20905         return (this.DDM.isLocked() || this.locked);
20906     },
20907
20908     /**
20909      * Fired when this object is clicked
20910      * @method handleMouseDown
20911      * @param {Event} e
20912      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20913      * @private
20914      */
20915     handleMouseDown: function(e, oDD){
20916      
20917         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20918             //Roo.log('not touch/ button !=0');
20919             return;
20920         }
20921         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20922             return; // double touch..
20923         }
20924         
20925
20926         if (this.isLocked()) {
20927             //Roo.log('locked');
20928             return;
20929         }
20930
20931         this.DDM.refreshCache(this.groups);
20932 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20933         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20934         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20935             //Roo.log('no outer handes or not over target');
20936                 // do nothing.
20937         } else {
20938 //            Roo.log('check validator');
20939             if (this.clickValidator(e)) {
20940 //                Roo.log('validate success');
20941                 // set the initial element position
20942                 this.setStartPosition();
20943
20944
20945                 this.b4MouseDown(e);
20946                 this.onMouseDown(e);
20947
20948                 this.DDM.handleMouseDown(e, this);
20949
20950                 this.DDM.stopEvent(e);
20951             } else {
20952
20953
20954             }
20955         }
20956     },
20957
20958     clickValidator: function(e) {
20959         var target = e.getTarget();
20960         return ( this.isValidHandleChild(target) &&
20961                     (this.id == this.handleElId ||
20962                         this.DDM.handleWasClicked(target, this.id)) );
20963     },
20964
20965     /**
20966      * Allows you to specify a tag name that should not start a drag operation
20967      * when clicked.  This is designed to facilitate embedding links within a
20968      * drag handle that do something other than start the drag.
20969      * @method addInvalidHandleType
20970      * @param {string} tagName the type of element to exclude
20971      */
20972     addInvalidHandleType: function(tagName) {
20973         var type = tagName.toUpperCase();
20974         this.invalidHandleTypes[type] = type;
20975     },
20976
20977     /**
20978      * Lets you to specify an element id for a child of a drag handle
20979      * that should not initiate a drag
20980      * @method addInvalidHandleId
20981      * @param {string} id the element id of the element you wish to ignore
20982      */
20983     addInvalidHandleId: function(id) {
20984         if (typeof id !== "string") {
20985             id = Roo.id(id);
20986         }
20987         this.invalidHandleIds[id] = id;
20988     },
20989
20990     /**
20991      * Lets you specify a css class of elements that will not initiate a drag
20992      * @method addInvalidHandleClass
20993      * @param {string} cssClass the class of the elements you wish to ignore
20994      */
20995     addInvalidHandleClass: function(cssClass) {
20996         this.invalidHandleClasses.push(cssClass);
20997     },
20998
20999     /**
21000      * Unsets an excluded tag name set by addInvalidHandleType
21001      * @method removeInvalidHandleType
21002      * @param {string} tagName the type of element to unexclude
21003      */
21004     removeInvalidHandleType: function(tagName) {
21005         var type = tagName.toUpperCase();
21006         // this.invalidHandleTypes[type] = null;
21007         delete this.invalidHandleTypes[type];
21008     },
21009
21010     /**
21011      * Unsets an invalid handle id
21012      * @method removeInvalidHandleId
21013      * @param {string} id the id of the element to re-enable
21014      */
21015     removeInvalidHandleId: function(id) {
21016         if (typeof id !== "string") {
21017             id = Roo.id(id);
21018         }
21019         delete this.invalidHandleIds[id];
21020     },
21021
21022     /**
21023      * Unsets an invalid css class
21024      * @method removeInvalidHandleClass
21025      * @param {string} cssClass the class of the element(s) you wish to
21026      * re-enable
21027      */
21028     removeInvalidHandleClass: function(cssClass) {
21029         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21030             if (this.invalidHandleClasses[i] == cssClass) {
21031                 delete this.invalidHandleClasses[i];
21032             }
21033         }
21034     },
21035
21036     /**
21037      * Checks the tag exclusion list to see if this click should be ignored
21038      * @method isValidHandleChild
21039      * @param {HTMLElement} node the HTMLElement to evaluate
21040      * @return {boolean} true if this is a valid tag type, false if not
21041      */
21042     isValidHandleChild: function(node) {
21043
21044         var valid = true;
21045         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21046         var nodeName;
21047         try {
21048             nodeName = node.nodeName.toUpperCase();
21049         } catch(e) {
21050             nodeName = node.nodeName;
21051         }
21052         valid = valid && !this.invalidHandleTypes[nodeName];
21053         valid = valid && !this.invalidHandleIds[node.id];
21054
21055         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21056             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21057         }
21058
21059
21060         return valid;
21061
21062     },
21063
21064     /**
21065      * Create the array of horizontal tick marks if an interval was specified
21066      * in setXConstraint().
21067      * @method setXTicks
21068      * @private
21069      */
21070     setXTicks: function(iStartX, iTickSize) {
21071         this.xTicks = [];
21072         this.xTickSize = iTickSize;
21073
21074         var tickMap = {};
21075
21076         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21077             if (!tickMap[i]) {
21078                 this.xTicks[this.xTicks.length] = i;
21079                 tickMap[i] = true;
21080             }
21081         }
21082
21083         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21084             if (!tickMap[i]) {
21085                 this.xTicks[this.xTicks.length] = i;
21086                 tickMap[i] = true;
21087             }
21088         }
21089
21090         this.xTicks.sort(this.DDM.numericSort) ;
21091     },
21092
21093     /**
21094      * Create the array of vertical tick marks if an interval was specified in
21095      * setYConstraint().
21096      * @method setYTicks
21097      * @private
21098      */
21099     setYTicks: function(iStartY, iTickSize) {
21100         this.yTicks = [];
21101         this.yTickSize = iTickSize;
21102
21103         var tickMap = {};
21104
21105         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21106             if (!tickMap[i]) {
21107                 this.yTicks[this.yTicks.length] = i;
21108                 tickMap[i] = true;
21109             }
21110         }
21111
21112         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21113             if (!tickMap[i]) {
21114                 this.yTicks[this.yTicks.length] = i;
21115                 tickMap[i] = true;
21116             }
21117         }
21118
21119         this.yTicks.sort(this.DDM.numericSort) ;
21120     },
21121
21122     /**
21123      * By default, the element can be dragged any place on the screen.  Use
21124      * this method to limit the horizontal travel of the element.  Pass in
21125      * 0,0 for the parameters if you want to lock the drag to the y axis.
21126      * @method setXConstraint
21127      * @param {int} iLeft the number of pixels the element can move to the left
21128      * @param {int} iRight the number of pixels the element can move to the
21129      * right
21130      * @param {int} iTickSize optional parameter for specifying that the
21131      * element
21132      * should move iTickSize pixels at a time.
21133      */
21134     setXConstraint: function(iLeft, iRight, iTickSize) {
21135         this.leftConstraint = iLeft;
21136         this.rightConstraint = iRight;
21137
21138         this.minX = this.initPageX - iLeft;
21139         this.maxX = this.initPageX + iRight;
21140         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21141
21142         this.constrainX = true;
21143     },
21144
21145     /**
21146      * Clears any constraints applied to this instance.  Also clears ticks
21147      * since they can't exist independent of a constraint at this time.
21148      * @method clearConstraints
21149      */
21150     clearConstraints: function() {
21151         this.constrainX = false;
21152         this.constrainY = false;
21153         this.clearTicks();
21154     },
21155
21156     /**
21157      * Clears any tick interval defined for this instance
21158      * @method clearTicks
21159      */
21160     clearTicks: function() {
21161         this.xTicks = null;
21162         this.yTicks = null;
21163         this.xTickSize = 0;
21164         this.yTickSize = 0;
21165     },
21166
21167     /**
21168      * By default, the element can be dragged any place on the screen.  Set
21169      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21170      * parameters if you want to lock the drag to the x axis.
21171      * @method setYConstraint
21172      * @param {int} iUp the number of pixels the element can move up
21173      * @param {int} iDown the number of pixels the element can move down
21174      * @param {int} iTickSize optional parameter for specifying that the
21175      * element should move iTickSize pixels at a time.
21176      */
21177     setYConstraint: function(iUp, iDown, iTickSize) {
21178         this.topConstraint = iUp;
21179         this.bottomConstraint = iDown;
21180
21181         this.minY = this.initPageY - iUp;
21182         this.maxY = this.initPageY + iDown;
21183         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21184
21185         this.constrainY = true;
21186
21187     },
21188
21189     /**
21190      * resetConstraints must be called if you manually reposition a dd element.
21191      * @method resetConstraints
21192      * @param {boolean} maintainOffset
21193      */
21194     resetConstraints: function() {
21195
21196
21197         // Maintain offsets if necessary
21198         if (this.initPageX || this.initPageX === 0) {
21199             // figure out how much this thing has moved
21200             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21201             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21202
21203             this.setInitPosition(dx, dy);
21204
21205         // This is the first time we have detected the element's position
21206         } else {
21207             this.setInitPosition();
21208         }
21209
21210         if (this.constrainX) {
21211             this.setXConstraint( this.leftConstraint,
21212                                  this.rightConstraint,
21213                                  this.xTickSize        );
21214         }
21215
21216         if (this.constrainY) {
21217             this.setYConstraint( this.topConstraint,
21218                                  this.bottomConstraint,
21219                                  this.yTickSize         );
21220         }
21221     },
21222
21223     /**
21224      * Normally the drag element is moved pixel by pixel, but we can specify
21225      * that it move a number of pixels at a time.  This method resolves the
21226      * location when we have it set up like this.
21227      * @method getTick
21228      * @param {int} val where we want to place the object
21229      * @param {int[]} tickArray sorted array of valid points
21230      * @return {int} the closest tick
21231      * @private
21232      */
21233     getTick: function(val, tickArray) {
21234
21235         if (!tickArray) {
21236             // If tick interval is not defined, it is effectively 1 pixel,
21237             // so we return the value passed to us.
21238             return val;
21239         } else if (tickArray[0] >= val) {
21240             // The value is lower than the first tick, so we return the first
21241             // tick.
21242             return tickArray[0];
21243         } else {
21244             for (var i=0, len=tickArray.length; i<len; ++i) {
21245                 var next = i + 1;
21246                 if (tickArray[next] && tickArray[next] >= val) {
21247                     var diff1 = val - tickArray[i];
21248                     var diff2 = tickArray[next] - val;
21249                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21250                 }
21251             }
21252
21253             // The value is larger than the last tick, so we return the last
21254             // tick.
21255             return tickArray[tickArray.length - 1];
21256         }
21257     },
21258
21259     /**
21260      * toString method
21261      * @method toString
21262      * @return {string} string representation of the dd obj
21263      */
21264     toString: function() {
21265         return ("DragDrop " + this.id);
21266     }
21267
21268 });
21269
21270 })();
21271 /*
21272  * Based on:
21273  * Ext JS Library 1.1.1
21274  * Copyright(c) 2006-2007, Ext JS, LLC.
21275  *
21276  * Originally Released Under LGPL - original licence link has changed is not relivant.
21277  *
21278  * Fork - LGPL
21279  * <script type="text/javascript">
21280  */
21281
21282
21283 /**
21284  * The drag and drop utility provides a framework for building drag and drop
21285  * applications.  In addition to enabling drag and drop for specific elements,
21286  * the drag and drop elements are tracked by the manager class, and the
21287  * interactions between the various elements are tracked during the drag and
21288  * the implementing code is notified about these important moments.
21289  */
21290
21291 // Only load the library once.  Rewriting the manager class would orphan
21292 // existing drag and drop instances.
21293 if (!Roo.dd.DragDropMgr) {
21294
21295 /**
21296  * @class Roo.dd.DragDropMgr
21297  * DragDropMgr is a singleton that tracks the element interaction for
21298  * all DragDrop items in the window.  Generally, you will not call
21299  * this class directly, but it does have helper methods that could
21300  * be useful in your DragDrop implementations.
21301  * @static
21302  */
21303 Roo.dd.DragDropMgr = function() {
21304
21305     var Event = Roo.EventManager;
21306
21307     return {
21308
21309         /**
21310          * Two dimensional Array of registered DragDrop objects.  The first
21311          * dimension is the DragDrop item group, the second the DragDrop
21312          * object.
21313          * @property ids
21314          * @type {string: string}
21315          * @private
21316          * @static
21317          */
21318         ids: {},
21319
21320         /**
21321          * Array of element ids defined as drag handles.  Used to determine
21322          * if the element that generated the mousedown event is actually the
21323          * handle and not the html element itself.
21324          * @property handleIds
21325          * @type {string: string}
21326          * @private
21327          * @static
21328          */
21329         handleIds: {},
21330
21331         /**
21332          * the DragDrop object that is currently being dragged
21333          * @property dragCurrent
21334          * @type DragDrop
21335          * @private
21336          * @static
21337          **/
21338         dragCurrent: null,
21339
21340         /**
21341          * the DragDrop object(s) that are being hovered over
21342          * @property dragOvers
21343          * @type Array
21344          * @private
21345          * @static
21346          */
21347         dragOvers: {},
21348
21349         /**
21350          * the X distance between the cursor and the object being dragged
21351          * @property deltaX
21352          * @type int
21353          * @private
21354          * @static
21355          */
21356         deltaX: 0,
21357
21358         /**
21359          * the Y distance between the cursor and the object being dragged
21360          * @property deltaY
21361          * @type int
21362          * @private
21363          * @static
21364          */
21365         deltaY: 0,
21366
21367         /**
21368          * Flag to determine if we should prevent the default behavior of the
21369          * events we define. By default this is true, but this can be set to
21370          * false if you need the default behavior (not recommended)
21371          * @property preventDefault
21372          * @type boolean
21373          * @static
21374          */
21375         preventDefault: true,
21376
21377         /**
21378          * Flag to determine if we should stop the propagation of the events
21379          * we generate. This is true by default but you may want to set it to
21380          * false if the html element contains other features that require the
21381          * mouse click.
21382          * @property stopPropagation
21383          * @type boolean
21384          * @static
21385          */
21386         stopPropagation: true,
21387
21388         /**
21389          * Internal flag that is set to true when drag and drop has been
21390          * intialized
21391          * @property initialized
21392          * @private
21393          * @static
21394          */
21395         initalized: false,
21396
21397         /**
21398          * All drag and drop can be disabled.
21399          * @property locked
21400          * @private
21401          * @static
21402          */
21403         locked: false,
21404
21405         /**
21406          * Called the first time an element is registered.
21407          * @method init
21408          * @private
21409          * @static
21410          */
21411         init: function() {
21412             this.initialized = true;
21413         },
21414
21415         /**
21416          * In point mode, drag and drop interaction is defined by the
21417          * location of the cursor during the drag/drop
21418          * @property POINT
21419          * @type int
21420          * @static
21421          */
21422         POINT: 0,
21423
21424         /**
21425          * In intersect mode, drag and drop interactio nis defined by the
21426          * overlap of two or more drag and drop objects.
21427          * @property INTERSECT
21428          * @type int
21429          * @static
21430          */
21431         INTERSECT: 1,
21432
21433         /**
21434          * The current drag and drop mode.  Default: POINT
21435          * @property mode
21436          * @type int
21437          * @static
21438          */
21439         mode: 0,
21440
21441         /**
21442          * Runs method on all drag and drop objects
21443          * @method _execOnAll
21444          * @private
21445          * @static
21446          */
21447         _execOnAll: function(sMethod, args) {
21448             for (var i in this.ids) {
21449                 for (var j in this.ids[i]) {
21450                     var oDD = this.ids[i][j];
21451                     if (! this.isTypeOfDD(oDD)) {
21452                         continue;
21453                     }
21454                     oDD[sMethod].apply(oDD, args);
21455                 }
21456             }
21457         },
21458
21459         /**
21460          * Drag and drop initialization.  Sets up the global event handlers
21461          * @method _onLoad
21462          * @private
21463          * @static
21464          */
21465         _onLoad: function() {
21466
21467             this.init();
21468
21469             if (!Roo.isTouch) {
21470                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21471                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21472             }
21473             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21474             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21475             
21476             Event.on(window,   "unload",    this._onUnload, this, true);
21477             Event.on(window,   "resize",    this._onResize, this, true);
21478             // Event.on(window,   "mouseout",    this._test);
21479
21480         },
21481
21482         /**
21483          * Reset constraints on all drag and drop objs
21484          * @method _onResize
21485          * @private
21486          * @static
21487          */
21488         _onResize: function(e) {
21489             this._execOnAll("resetConstraints", []);
21490         },
21491
21492         /**
21493          * Lock all drag and drop functionality
21494          * @method lock
21495          * @static
21496          */
21497         lock: function() { this.locked = true; },
21498
21499         /**
21500          * Unlock all drag and drop functionality
21501          * @method unlock
21502          * @static
21503          */
21504         unlock: function() { this.locked = false; },
21505
21506         /**
21507          * Is drag and drop locked?
21508          * @method isLocked
21509          * @return {boolean} True if drag and drop is locked, false otherwise.
21510          * @static
21511          */
21512         isLocked: function() { return this.locked; },
21513
21514         /**
21515          * Location cache that is set for all drag drop objects when a drag is
21516          * initiated, cleared when the drag is finished.
21517          * @property locationCache
21518          * @private
21519          * @static
21520          */
21521         locationCache: {},
21522
21523         /**
21524          * Set useCache to false if you want to force object the lookup of each
21525          * drag and drop linked element constantly during a drag.
21526          * @property useCache
21527          * @type boolean
21528          * @static
21529          */
21530         useCache: true,
21531
21532         /**
21533          * The number of pixels that the mouse needs to move after the
21534          * mousedown before the drag is initiated.  Default=3;
21535          * @property clickPixelThresh
21536          * @type int
21537          * @static
21538          */
21539         clickPixelThresh: 3,
21540
21541         /**
21542          * The number of milliseconds after the mousedown event to initiate the
21543          * drag if we don't get a mouseup event. Default=1000
21544          * @property clickTimeThresh
21545          * @type int
21546          * @static
21547          */
21548         clickTimeThresh: 350,
21549
21550         /**
21551          * Flag that indicates that either the drag pixel threshold or the
21552          * mousdown time threshold has been met
21553          * @property dragThreshMet
21554          * @type boolean
21555          * @private
21556          * @static
21557          */
21558         dragThreshMet: false,
21559
21560         /**
21561          * Timeout used for the click time threshold
21562          * @property clickTimeout
21563          * @type Object
21564          * @private
21565          * @static
21566          */
21567         clickTimeout: null,
21568
21569         /**
21570          * The X position of the mousedown event stored for later use when a
21571          * drag threshold is met.
21572          * @property startX
21573          * @type int
21574          * @private
21575          * @static
21576          */
21577         startX: 0,
21578
21579         /**
21580          * The Y position of the mousedown event stored for later use when a
21581          * drag threshold is met.
21582          * @property startY
21583          * @type int
21584          * @private
21585          * @static
21586          */
21587         startY: 0,
21588
21589         /**
21590          * Each DragDrop instance must be registered with the DragDropMgr.
21591          * This is executed in DragDrop.init()
21592          * @method regDragDrop
21593          * @param {DragDrop} oDD the DragDrop object to register
21594          * @param {String} sGroup the name of the group this element belongs to
21595          * @static
21596          */
21597         regDragDrop: function(oDD, sGroup) {
21598             if (!this.initialized) { this.init(); }
21599
21600             if (!this.ids[sGroup]) {
21601                 this.ids[sGroup] = {};
21602             }
21603             this.ids[sGroup][oDD.id] = oDD;
21604         },
21605
21606         /**
21607          * Removes the supplied dd instance from the supplied group. Executed
21608          * by DragDrop.removeFromGroup, so don't call this function directly.
21609          * @method removeDDFromGroup
21610          * @private
21611          * @static
21612          */
21613         removeDDFromGroup: function(oDD, sGroup) {
21614             if (!this.ids[sGroup]) {
21615                 this.ids[sGroup] = {};
21616             }
21617
21618             var obj = this.ids[sGroup];
21619             if (obj && obj[oDD.id]) {
21620                 delete obj[oDD.id];
21621             }
21622         },
21623
21624         /**
21625          * Unregisters a drag and drop item.  This is executed in
21626          * DragDrop.unreg, use that method instead of calling this directly.
21627          * @method _remove
21628          * @private
21629          * @static
21630          */
21631         _remove: function(oDD) {
21632             for (var g in oDD.groups) {
21633                 if (g && this.ids[g][oDD.id]) {
21634                     delete this.ids[g][oDD.id];
21635                 }
21636             }
21637             delete this.handleIds[oDD.id];
21638         },
21639
21640         /**
21641          * Each DragDrop handle element must be registered.  This is done
21642          * automatically when executing DragDrop.setHandleElId()
21643          * @method regHandle
21644          * @param {String} sDDId the DragDrop id this element is a handle for
21645          * @param {String} sHandleId the id of the element that is the drag
21646          * handle
21647          * @static
21648          */
21649         regHandle: function(sDDId, sHandleId) {
21650             if (!this.handleIds[sDDId]) {
21651                 this.handleIds[sDDId] = {};
21652             }
21653             this.handleIds[sDDId][sHandleId] = sHandleId;
21654         },
21655
21656         /**
21657          * Utility function to determine if a given element has been
21658          * registered as a drag drop item.
21659          * @method isDragDrop
21660          * @param {String} id the element id to check
21661          * @return {boolean} true if this element is a DragDrop item,
21662          * false otherwise
21663          * @static
21664          */
21665         isDragDrop: function(id) {
21666             return ( this.getDDById(id) ) ? true : false;
21667         },
21668
21669         /**
21670          * Returns the drag and drop instances that are in all groups the
21671          * passed in instance belongs to.
21672          * @method getRelated
21673          * @param {DragDrop} p_oDD the obj to get related data for
21674          * @param {boolean} bTargetsOnly if true, only return targetable objs
21675          * @return {DragDrop[]} the related instances
21676          * @static
21677          */
21678         getRelated: function(p_oDD, bTargetsOnly) {
21679             var oDDs = [];
21680             for (var i in p_oDD.groups) {
21681                 for (j in this.ids[i]) {
21682                     var dd = this.ids[i][j];
21683                     if (! this.isTypeOfDD(dd)) {
21684                         continue;
21685                     }
21686                     if (!bTargetsOnly || dd.isTarget) {
21687                         oDDs[oDDs.length] = dd;
21688                     }
21689                 }
21690             }
21691
21692             return oDDs;
21693         },
21694
21695         /**
21696          * Returns true if the specified dd target is a legal target for
21697          * the specifice drag obj
21698          * @method isLegalTarget
21699          * @param {DragDrop} the drag obj
21700          * @param {DragDrop} the target
21701          * @return {boolean} true if the target is a legal target for the
21702          * dd obj
21703          * @static
21704          */
21705         isLegalTarget: function (oDD, oTargetDD) {
21706             var targets = this.getRelated(oDD, true);
21707             for (var i=0, len=targets.length;i<len;++i) {
21708                 if (targets[i].id == oTargetDD.id) {
21709                     return true;
21710                 }
21711             }
21712
21713             return false;
21714         },
21715
21716         /**
21717          * My goal is to be able to transparently determine if an object is
21718          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21719          * returns "object", oDD.constructor.toString() always returns
21720          * "DragDrop" and not the name of the subclass.  So for now it just
21721          * evaluates a well-known variable in DragDrop.
21722          * @method isTypeOfDD
21723          * @param {Object} the object to evaluate
21724          * @return {boolean} true if typeof oDD = DragDrop
21725          * @static
21726          */
21727         isTypeOfDD: function (oDD) {
21728             return (oDD && oDD.__ygDragDrop);
21729         },
21730
21731         /**
21732          * Utility function to determine if a given element has been
21733          * registered as a drag drop handle for the given Drag Drop object.
21734          * @method isHandle
21735          * @param {String} id the element id to check
21736          * @return {boolean} true if this element is a DragDrop handle, false
21737          * otherwise
21738          * @static
21739          */
21740         isHandle: function(sDDId, sHandleId) {
21741             return ( this.handleIds[sDDId] &&
21742                             this.handleIds[sDDId][sHandleId] );
21743         },
21744
21745         /**
21746          * Returns the DragDrop instance for a given id
21747          * @method getDDById
21748          * @param {String} id the id of the DragDrop object
21749          * @return {DragDrop} the drag drop object, null if it is not found
21750          * @static
21751          */
21752         getDDById: function(id) {
21753             for (var i in this.ids) {
21754                 if (this.ids[i][id]) {
21755                     return this.ids[i][id];
21756                 }
21757             }
21758             return null;
21759         },
21760
21761         /**
21762          * Fired after a registered DragDrop object gets the mousedown event.
21763          * Sets up the events required to track the object being dragged
21764          * @method handleMouseDown
21765          * @param {Event} e the event
21766          * @param oDD the DragDrop object being dragged
21767          * @private
21768          * @static
21769          */
21770         handleMouseDown: function(e, oDD) {
21771             if(Roo.QuickTips){
21772                 Roo.QuickTips.disable();
21773             }
21774             this.currentTarget = e.getTarget();
21775
21776             this.dragCurrent = oDD;
21777
21778             var el = oDD.getEl();
21779
21780             // track start position
21781             this.startX = e.getPageX();
21782             this.startY = e.getPageY();
21783
21784             this.deltaX = this.startX - el.offsetLeft;
21785             this.deltaY = this.startY - el.offsetTop;
21786
21787             this.dragThreshMet = false;
21788
21789             this.clickTimeout = setTimeout(
21790                     function() {
21791                         var DDM = Roo.dd.DDM;
21792                         DDM.startDrag(DDM.startX, DDM.startY);
21793                     },
21794                     this.clickTimeThresh );
21795         },
21796
21797         /**
21798          * Fired when either the drag pixel threshol or the mousedown hold
21799          * time threshold has been met.
21800          * @method startDrag
21801          * @param x {int} the X position of the original mousedown
21802          * @param y {int} the Y position of the original mousedown
21803          * @static
21804          */
21805         startDrag: function(x, y) {
21806             clearTimeout(this.clickTimeout);
21807             if (this.dragCurrent) {
21808                 this.dragCurrent.b4StartDrag(x, y);
21809                 this.dragCurrent.startDrag(x, y);
21810             }
21811             this.dragThreshMet = true;
21812         },
21813
21814         /**
21815          * Internal function to handle the mouseup event.  Will be invoked
21816          * from the context of the document.
21817          * @method handleMouseUp
21818          * @param {Event} e the event
21819          * @private
21820          * @static
21821          */
21822         handleMouseUp: function(e) {
21823
21824             if(Roo.QuickTips){
21825                 Roo.QuickTips.enable();
21826             }
21827             if (! this.dragCurrent) {
21828                 return;
21829             }
21830
21831             clearTimeout(this.clickTimeout);
21832
21833             if (this.dragThreshMet) {
21834                 this.fireEvents(e, true);
21835             } else {
21836             }
21837
21838             this.stopDrag(e);
21839
21840             this.stopEvent(e);
21841         },
21842
21843         /**
21844          * Utility to stop event propagation and event default, if these
21845          * features are turned on.
21846          * @method stopEvent
21847          * @param {Event} e the event as returned by this.getEvent()
21848          * @static
21849          */
21850         stopEvent: function(e){
21851             if(this.stopPropagation) {
21852                 e.stopPropagation();
21853             }
21854
21855             if (this.preventDefault) {
21856                 e.preventDefault();
21857             }
21858         },
21859
21860         /**
21861          * Internal function to clean up event handlers after the drag
21862          * operation is complete
21863          * @method stopDrag
21864          * @param {Event} e the event
21865          * @private
21866          * @static
21867          */
21868         stopDrag: function(e) {
21869             // Fire the drag end event for the item that was dragged
21870             if (this.dragCurrent) {
21871                 if (this.dragThreshMet) {
21872                     this.dragCurrent.b4EndDrag(e);
21873                     this.dragCurrent.endDrag(e);
21874                 }
21875
21876                 this.dragCurrent.onMouseUp(e);
21877             }
21878
21879             this.dragCurrent = null;
21880             this.dragOvers = {};
21881         },
21882
21883         /**
21884          * Internal function to handle the mousemove event.  Will be invoked
21885          * from the context of the html element.
21886          *
21887          * @TODO figure out what we can do about mouse events lost when the
21888          * user drags objects beyond the window boundary.  Currently we can
21889          * detect this in internet explorer by verifying that the mouse is
21890          * down during the mousemove event.  Firefox doesn't give us the
21891          * button state on the mousemove event.
21892          * @method handleMouseMove
21893          * @param {Event} e the event
21894          * @private
21895          * @static
21896          */
21897         handleMouseMove: function(e) {
21898             if (! this.dragCurrent) {
21899                 return true;
21900             }
21901
21902             // var button = e.which || e.button;
21903
21904             // check for IE mouseup outside of page boundary
21905             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21906                 this.stopEvent(e);
21907                 return this.handleMouseUp(e);
21908             }
21909
21910             if (!this.dragThreshMet) {
21911                 var diffX = Math.abs(this.startX - e.getPageX());
21912                 var diffY = Math.abs(this.startY - e.getPageY());
21913                 if (diffX > this.clickPixelThresh ||
21914                             diffY > this.clickPixelThresh) {
21915                     this.startDrag(this.startX, this.startY);
21916                 }
21917             }
21918
21919             if (this.dragThreshMet) {
21920                 this.dragCurrent.b4Drag(e);
21921                 this.dragCurrent.onDrag(e);
21922                 if(!this.dragCurrent.moveOnly){
21923                     this.fireEvents(e, false);
21924                 }
21925             }
21926
21927             this.stopEvent(e);
21928
21929             return true;
21930         },
21931
21932         /**
21933          * Iterates over all of the DragDrop elements to find ones we are
21934          * hovering over or dropping on
21935          * @method fireEvents
21936          * @param {Event} e the event
21937          * @param {boolean} isDrop is this a drop op or a mouseover op?
21938          * @private
21939          * @static
21940          */
21941         fireEvents: function(e, isDrop) {
21942             var dc = this.dragCurrent;
21943
21944             // If the user did the mouse up outside of the window, we could
21945             // get here even though we have ended the drag.
21946             if (!dc || dc.isLocked()) {
21947                 return;
21948             }
21949
21950             var pt = e.getPoint();
21951
21952             // cache the previous dragOver array
21953             var oldOvers = [];
21954
21955             var outEvts   = [];
21956             var overEvts  = [];
21957             var dropEvts  = [];
21958             var enterEvts = [];
21959
21960             // Check to see if the object(s) we were hovering over is no longer
21961             // being hovered over so we can fire the onDragOut event
21962             for (var i in this.dragOvers) {
21963
21964                 var ddo = this.dragOvers[i];
21965
21966                 if (! this.isTypeOfDD(ddo)) {
21967                     continue;
21968                 }
21969
21970                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21971                     outEvts.push( ddo );
21972                 }
21973
21974                 oldOvers[i] = true;
21975                 delete this.dragOvers[i];
21976             }
21977
21978             for (var sGroup in dc.groups) {
21979
21980                 if ("string" != typeof sGroup) {
21981                     continue;
21982                 }
21983
21984                 for (i in this.ids[sGroup]) {
21985                     var oDD = this.ids[sGroup][i];
21986                     if (! this.isTypeOfDD(oDD)) {
21987                         continue;
21988                     }
21989
21990                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21991                         if (this.isOverTarget(pt, oDD, this.mode)) {
21992                             // look for drop interactions
21993                             if (isDrop) {
21994                                 dropEvts.push( oDD );
21995                             // look for drag enter and drag over interactions
21996                             } else {
21997
21998                                 // initial drag over: dragEnter fires
21999                                 if (!oldOvers[oDD.id]) {
22000                                     enterEvts.push( oDD );
22001                                 // subsequent drag overs: dragOver fires
22002                                 } else {
22003                                     overEvts.push( oDD );
22004                                 }
22005
22006                                 this.dragOvers[oDD.id] = oDD;
22007                             }
22008                         }
22009                     }
22010                 }
22011             }
22012
22013             if (this.mode) {
22014                 if (outEvts.length) {
22015                     dc.b4DragOut(e, outEvts);
22016                     dc.onDragOut(e, outEvts);
22017                 }
22018
22019                 if (enterEvts.length) {
22020                     dc.onDragEnter(e, enterEvts);
22021                 }
22022
22023                 if (overEvts.length) {
22024                     dc.b4DragOver(e, overEvts);
22025                     dc.onDragOver(e, overEvts);
22026                 }
22027
22028                 if (dropEvts.length) {
22029                     dc.b4DragDrop(e, dropEvts);
22030                     dc.onDragDrop(e, dropEvts);
22031                 }
22032
22033             } else {
22034                 // fire dragout events
22035                 var len = 0;
22036                 for (i=0, len=outEvts.length; i<len; ++i) {
22037                     dc.b4DragOut(e, outEvts[i].id);
22038                     dc.onDragOut(e, outEvts[i].id);
22039                 }
22040
22041                 // fire enter events
22042                 for (i=0,len=enterEvts.length; i<len; ++i) {
22043                     // dc.b4DragEnter(e, oDD.id);
22044                     dc.onDragEnter(e, enterEvts[i].id);
22045                 }
22046
22047                 // fire over events
22048                 for (i=0,len=overEvts.length; i<len; ++i) {
22049                     dc.b4DragOver(e, overEvts[i].id);
22050                     dc.onDragOver(e, overEvts[i].id);
22051                 }
22052
22053                 // fire drop events
22054                 for (i=0, len=dropEvts.length; i<len; ++i) {
22055                     dc.b4DragDrop(e, dropEvts[i].id);
22056                     dc.onDragDrop(e, dropEvts[i].id);
22057                 }
22058
22059             }
22060
22061             // notify about a drop that did not find a target
22062             if (isDrop && !dropEvts.length) {
22063                 dc.onInvalidDrop(e);
22064             }
22065
22066         },
22067
22068         /**
22069          * Helper function for getting the best match from the list of drag
22070          * and drop objects returned by the drag and drop events when we are
22071          * in INTERSECT mode.  It returns either the first object that the
22072          * cursor is over, or the object that has the greatest overlap with
22073          * the dragged element.
22074          * @method getBestMatch
22075          * @param  {DragDrop[]} dds The array of drag and drop objects
22076          * targeted
22077          * @return {DragDrop}       The best single match
22078          * @static
22079          */
22080         getBestMatch: function(dds) {
22081             var winner = null;
22082             // Return null if the input is not what we expect
22083             //if (!dds || !dds.length || dds.length == 0) {
22084                // winner = null;
22085             // If there is only one item, it wins
22086             //} else if (dds.length == 1) {
22087
22088             var len = dds.length;
22089
22090             if (len == 1) {
22091                 winner = dds[0];
22092             } else {
22093                 // Loop through the targeted items
22094                 for (var i=0; i<len; ++i) {
22095                     var dd = dds[i];
22096                     // If the cursor is over the object, it wins.  If the
22097                     // cursor is over multiple matches, the first one we come
22098                     // to wins.
22099                     if (dd.cursorIsOver) {
22100                         winner = dd;
22101                         break;
22102                     // Otherwise the object with the most overlap wins
22103                     } else {
22104                         if (!winner ||
22105                             winner.overlap.getArea() < dd.overlap.getArea()) {
22106                             winner = dd;
22107                         }
22108                     }
22109                 }
22110             }
22111
22112             return winner;
22113         },
22114
22115         /**
22116          * Refreshes the cache of the top-left and bottom-right points of the
22117          * drag and drop objects in the specified group(s).  This is in the
22118          * format that is stored in the drag and drop instance, so typical
22119          * usage is:
22120          * <code>
22121          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22122          * </code>
22123          * Alternatively:
22124          * <code>
22125          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22126          * </code>
22127          * @TODO this really should be an indexed array.  Alternatively this
22128          * method could accept both.
22129          * @method refreshCache
22130          * @param {Object} groups an associative array of groups to refresh
22131          * @static
22132          */
22133         refreshCache: function(groups) {
22134             for (var sGroup in groups) {
22135                 if ("string" != typeof sGroup) {
22136                     continue;
22137                 }
22138                 for (var i in this.ids[sGroup]) {
22139                     var oDD = this.ids[sGroup][i];
22140
22141                     if (this.isTypeOfDD(oDD)) {
22142                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22143                         var loc = this.getLocation(oDD);
22144                         if (loc) {
22145                             this.locationCache[oDD.id] = loc;
22146                         } else {
22147                             delete this.locationCache[oDD.id];
22148                             // this will unregister the drag and drop object if
22149                             // the element is not in a usable state
22150                             // oDD.unreg();
22151                         }
22152                     }
22153                 }
22154             }
22155         },
22156
22157         /**
22158          * This checks to make sure an element exists and is in the DOM.  The
22159          * main purpose is to handle cases where innerHTML is used to remove
22160          * drag and drop objects from the DOM.  IE provides an 'unspecified
22161          * error' when trying to access the offsetParent of such an element
22162          * @method verifyEl
22163          * @param {HTMLElement} el the element to check
22164          * @return {boolean} true if the element looks usable
22165          * @static
22166          */
22167         verifyEl: function(el) {
22168             if (el) {
22169                 var parent;
22170                 if(Roo.isIE){
22171                     try{
22172                         parent = el.offsetParent;
22173                     }catch(e){}
22174                 }else{
22175                     parent = el.offsetParent;
22176                 }
22177                 if (parent) {
22178                     return true;
22179                 }
22180             }
22181
22182             return false;
22183         },
22184
22185         /**
22186          * Returns a Region object containing the drag and drop element's position
22187          * and size, including the padding configured for it
22188          * @method getLocation
22189          * @param {DragDrop} oDD the drag and drop object to get the
22190          *                       location for
22191          * @return {Roo.lib.Region} a Region object representing the total area
22192          *                             the element occupies, including any padding
22193          *                             the instance is configured for.
22194          * @static
22195          */
22196         getLocation: function(oDD) {
22197             if (! this.isTypeOfDD(oDD)) {
22198                 return null;
22199             }
22200
22201             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22202
22203             try {
22204                 pos= Roo.lib.Dom.getXY(el);
22205             } catch (e) { }
22206
22207             if (!pos) {
22208                 return null;
22209             }
22210
22211             x1 = pos[0];
22212             x2 = x1 + el.offsetWidth;
22213             y1 = pos[1];
22214             y2 = y1 + el.offsetHeight;
22215
22216             t = y1 - oDD.padding[0];
22217             r = x2 + oDD.padding[1];
22218             b = y2 + oDD.padding[2];
22219             l = x1 - oDD.padding[3];
22220
22221             return new Roo.lib.Region( t, r, b, l );
22222         },
22223
22224         /**
22225          * Checks the cursor location to see if it over the target
22226          * @method isOverTarget
22227          * @param {Roo.lib.Point} pt The point to evaluate
22228          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22229          * @return {boolean} true if the mouse is over the target
22230          * @private
22231          * @static
22232          */
22233         isOverTarget: function(pt, oTarget, intersect) {
22234             // use cache if available
22235             var loc = this.locationCache[oTarget.id];
22236             if (!loc || !this.useCache) {
22237                 loc = this.getLocation(oTarget);
22238                 this.locationCache[oTarget.id] = loc;
22239
22240             }
22241
22242             if (!loc) {
22243                 return false;
22244             }
22245
22246             oTarget.cursorIsOver = loc.contains( pt );
22247
22248             // DragDrop is using this as a sanity check for the initial mousedown
22249             // in this case we are done.  In POINT mode, if the drag obj has no
22250             // contraints, we are also done. Otherwise we need to evaluate the
22251             // location of the target as related to the actual location of the
22252             // dragged element.
22253             var dc = this.dragCurrent;
22254             if (!dc || !dc.getTargetCoord ||
22255                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22256                 return oTarget.cursorIsOver;
22257             }
22258
22259             oTarget.overlap = null;
22260
22261             // Get the current location of the drag element, this is the
22262             // location of the mouse event less the delta that represents
22263             // where the original mousedown happened on the element.  We
22264             // need to consider constraints and ticks as well.
22265             var pos = dc.getTargetCoord(pt.x, pt.y);
22266
22267             var el = dc.getDragEl();
22268             var curRegion = new Roo.lib.Region( pos.y,
22269                                                    pos.x + el.offsetWidth,
22270                                                    pos.y + el.offsetHeight,
22271                                                    pos.x );
22272
22273             var overlap = curRegion.intersect(loc);
22274
22275             if (overlap) {
22276                 oTarget.overlap = overlap;
22277                 return (intersect) ? true : oTarget.cursorIsOver;
22278             } else {
22279                 return false;
22280             }
22281         },
22282
22283         /**
22284          * unload event handler
22285          * @method _onUnload
22286          * @private
22287          * @static
22288          */
22289         _onUnload: function(e, me) {
22290             Roo.dd.DragDropMgr.unregAll();
22291         },
22292
22293         /**
22294          * Cleans up the drag and drop events and objects.
22295          * @method unregAll
22296          * @private
22297          * @static
22298          */
22299         unregAll: function() {
22300
22301             if (this.dragCurrent) {
22302                 this.stopDrag();
22303                 this.dragCurrent = null;
22304             }
22305
22306             this._execOnAll("unreg", []);
22307
22308             for (i in this.elementCache) {
22309                 delete this.elementCache[i];
22310             }
22311
22312             this.elementCache = {};
22313             this.ids = {};
22314         },
22315
22316         /**
22317          * A cache of DOM elements
22318          * @property elementCache
22319          * @private
22320          * @static
22321          */
22322         elementCache: {},
22323
22324         /**
22325          * Get the wrapper for the DOM element specified
22326          * @method getElWrapper
22327          * @param {String} id the id of the element to get
22328          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22329          * @private
22330          * @deprecated This wrapper isn't that useful
22331          * @static
22332          */
22333         getElWrapper: function(id) {
22334             var oWrapper = this.elementCache[id];
22335             if (!oWrapper || !oWrapper.el) {
22336                 oWrapper = this.elementCache[id] =
22337                     new this.ElementWrapper(Roo.getDom(id));
22338             }
22339             return oWrapper;
22340         },
22341
22342         /**
22343          * Returns the actual DOM element
22344          * @method getElement
22345          * @param {String} id the id of the elment to get
22346          * @return {Object} The element
22347          * @deprecated use Roo.getDom instead
22348          * @static
22349          */
22350         getElement: function(id) {
22351             return Roo.getDom(id);
22352         },
22353
22354         /**
22355          * Returns the style property for the DOM element (i.e.,
22356          * document.getElById(id).style)
22357          * @method getCss
22358          * @param {String} id the id of the elment to get
22359          * @return {Object} The style property of the element
22360          * @deprecated use Roo.getDom instead
22361          * @static
22362          */
22363         getCss: function(id) {
22364             var el = Roo.getDom(id);
22365             return (el) ? el.style : null;
22366         },
22367
22368         /**
22369          * Inner class for cached elements
22370          * @class DragDropMgr.ElementWrapper
22371          * @for DragDropMgr
22372          * @private
22373          * @deprecated
22374          */
22375         ElementWrapper: function(el) {
22376                 /**
22377                  * The element
22378                  * @property el
22379                  */
22380                 this.el = el || null;
22381                 /**
22382                  * The element id
22383                  * @property id
22384                  */
22385                 this.id = this.el && el.id;
22386                 /**
22387                  * A reference to the style property
22388                  * @property css
22389                  */
22390                 this.css = this.el && el.style;
22391             },
22392
22393         /**
22394          * Returns the X position of an html element
22395          * @method getPosX
22396          * @param el the element for which to get the position
22397          * @return {int} the X coordinate
22398          * @for DragDropMgr
22399          * @deprecated use Roo.lib.Dom.getX instead
22400          * @static
22401          */
22402         getPosX: function(el) {
22403             return Roo.lib.Dom.getX(el);
22404         },
22405
22406         /**
22407          * Returns the Y position of an html element
22408          * @method getPosY
22409          * @param el the element for which to get the position
22410          * @return {int} the Y coordinate
22411          * @deprecated use Roo.lib.Dom.getY instead
22412          * @static
22413          */
22414         getPosY: function(el) {
22415             return Roo.lib.Dom.getY(el);
22416         },
22417
22418         /**
22419          * Swap two nodes.  In IE, we use the native method, for others we
22420          * emulate the IE behavior
22421          * @method swapNode
22422          * @param n1 the first node to swap
22423          * @param n2 the other node to swap
22424          * @static
22425          */
22426         swapNode: function(n1, n2) {
22427             if (n1.swapNode) {
22428                 n1.swapNode(n2);
22429             } else {
22430                 var p = n2.parentNode;
22431                 var s = n2.nextSibling;
22432
22433                 if (s == n1) {
22434                     p.insertBefore(n1, n2);
22435                 } else if (n2 == n1.nextSibling) {
22436                     p.insertBefore(n2, n1);
22437                 } else {
22438                     n1.parentNode.replaceChild(n2, n1);
22439                     p.insertBefore(n1, s);
22440                 }
22441             }
22442         },
22443
22444         /**
22445          * Returns the current scroll position
22446          * @method getScroll
22447          * @private
22448          * @static
22449          */
22450         getScroll: function () {
22451             var t, l, dde=document.documentElement, db=document.body;
22452             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22453                 t = dde.scrollTop;
22454                 l = dde.scrollLeft;
22455             } else if (db) {
22456                 t = db.scrollTop;
22457                 l = db.scrollLeft;
22458             } else {
22459
22460             }
22461             return { top: t, left: l };
22462         },
22463
22464         /**
22465          * Returns the specified element style property
22466          * @method getStyle
22467          * @param {HTMLElement} el          the element
22468          * @param {string}      styleProp   the style property
22469          * @return {string} The value of the style property
22470          * @deprecated use Roo.lib.Dom.getStyle
22471          * @static
22472          */
22473         getStyle: function(el, styleProp) {
22474             return Roo.fly(el).getStyle(styleProp);
22475         },
22476
22477         /**
22478          * Gets the scrollTop
22479          * @method getScrollTop
22480          * @return {int} the document's scrollTop
22481          * @static
22482          */
22483         getScrollTop: function () { return this.getScroll().top; },
22484
22485         /**
22486          * Gets the scrollLeft
22487          * @method getScrollLeft
22488          * @return {int} the document's scrollTop
22489          * @static
22490          */
22491         getScrollLeft: function () { return this.getScroll().left; },
22492
22493         /**
22494          * Sets the x/y position of an element to the location of the
22495          * target element.
22496          * @method moveToEl
22497          * @param {HTMLElement} moveEl      The element to move
22498          * @param {HTMLElement} targetEl    The position reference element
22499          * @static
22500          */
22501         moveToEl: function (moveEl, targetEl) {
22502             var aCoord = Roo.lib.Dom.getXY(targetEl);
22503             Roo.lib.Dom.setXY(moveEl, aCoord);
22504         },
22505
22506         /**
22507          * Numeric array sort function
22508          * @method numericSort
22509          * @static
22510          */
22511         numericSort: function(a, b) { return (a - b); },
22512
22513         /**
22514          * Internal counter
22515          * @property _timeoutCount
22516          * @private
22517          * @static
22518          */
22519         _timeoutCount: 0,
22520
22521         /**
22522          * Trying to make the load order less important.  Without this we get
22523          * an error if this file is loaded before the Event Utility.
22524          * @method _addListeners
22525          * @private
22526          * @static
22527          */
22528         _addListeners: function() {
22529             var DDM = Roo.dd.DDM;
22530             if ( Roo.lib.Event && document ) {
22531                 DDM._onLoad();
22532             } else {
22533                 if (DDM._timeoutCount > 2000) {
22534                 } else {
22535                     setTimeout(DDM._addListeners, 10);
22536                     if (document && document.body) {
22537                         DDM._timeoutCount += 1;
22538                     }
22539                 }
22540             }
22541         },
22542
22543         /**
22544          * Recursively searches the immediate parent and all child nodes for
22545          * the handle element in order to determine wheter or not it was
22546          * clicked.
22547          * @method handleWasClicked
22548          * @param node the html element to inspect
22549          * @static
22550          */
22551         handleWasClicked: function(node, id) {
22552             if (this.isHandle(id, node.id)) {
22553                 return true;
22554             } else {
22555                 // check to see if this is a text node child of the one we want
22556                 var p = node.parentNode;
22557
22558                 while (p) {
22559                     if (this.isHandle(id, p.id)) {
22560                         return true;
22561                     } else {
22562                         p = p.parentNode;
22563                     }
22564                 }
22565             }
22566
22567             return false;
22568         }
22569
22570     };
22571
22572 }();
22573
22574 // shorter alias, save a few bytes
22575 Roo.dd.DDM = Roo.dd.DragDropMgr;
22576 Roo.dd.DDM._addListeners();
22577
22578 }/*
22579  * Based on:
22580  * Ext JS Library 1.1.1
22581  * Copyright(c) 2006-2007, Ext JS, LLC.
22582  *
22583  * Originally Released Under LGPL - original licence link has changed is not relivant.
22584  *
22585  * Fork - LGPL
22586  * <script type="text/javascript">
22587  */
22588
22589 /**
22590  * @class Roo.dd.DD
22591  * A DragDrop implementation where the linked element follows the
22592  * mouse cursor during a drag.
22593  * @extends Roo.dd.DragDrop
22594  * @constructor
22595  * @param {String} id the id of the linked element
22596  * @param {String} sGroup the group of related DragDrop items
22597  * @param {object} config an object containing configurable attributes
22598  *                Valid properties for DD:
22599  *                    scroll
22600  */
22601 Roo.dd.DD = function(id, sGroup, config) {
22602     if (id) {
22603         this.init(id, sGroup, config);
22604     }
22605 };
22606
22607 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22608
22609     /**
22610      * When set to true, the utility automatically tries to scroll the browser
22611      * window wehn a drag and drop element is dragged near the viewport boundary.
22612      * Defaults to true.
22613      * @property scroll
22614      * @type boolean
22615      */
22616     scroll: true,
22617
22618     /**
22619      * Sets the pointer offset to the distance between the linked element's top
22620      * left corner and the location the element was clicked
22621      * @method autoOffset
22622      * @param {int} iPageX the X coordinate of the click
22623      * @param {int} iPageY the Y coordinate of the click
22624      */
22625     autoOffset: function(iPageX, iPageY) {
22626         var x = iPageX - this.startPageX;
22627         var y = iPageY - this.startPageY;
22628         this.setDelta(x, y);
22629     },
22630
22631     /**
22632      * Sets the pointer offset.  You can call this directly to force the
22633      * offset to be in a particular location (e.g., pass in 0,0 to set it
22634      * to the center of the object)
22635      * @method setDelta
22636      * @param {int} iDeltaX the distance from the left
22637      * @param {int} iDeltaY the distance from the top
22638      */
22639     setDelta: function(iDeltaX, iDeltaY) {
22640         this.deltaX = iDeltaX;
22641         this.deltaY = iDeltaY;
22642     },
22643
22644     /**
22645      * Sets the drag element to the location of the mousedown or click event,
22646      * maintaining the cursor location relative to the location on the element
22647      * that was clicked.  Override this if you want to place the element in a
22648      * location other than where the cursor is.
22649      * @method setDragElPos
22650      * @param {int} iPageX the X coordinate of the mousedown or drag event
22651      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22652      */
22653     setDragElPos: function(iPageX, iPageY) {
22654         // the first time we do this, we are going to check to make sure
22655         // the element has css positioning
22656
22657         var el = this.getDragEl();
22658         this.alignElWithMouse(el, iPageX, iPageY);
22659     },
22660
22661     /**
22662      * Sets the element to the location of the mousedown or click event,
22663      * maintaining the cursor location relative to the location on the element
22664      * that was clicked.  Override this if you want to place the element in a
22665      * location other than where the cursor is.
22666      * @method alignElWithMouse
22667      * @param {HTMLElement} el the element to move
22668      * @param {int} iPageX the X coordinate of the mousedown or drag event
22669      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22670      */
22671     alignElWithMouse: function(el, iPageX, iPageY) {
22672         var oCoord = this.getTargetCoord(iPageX, iPageY);
22673         var fly = el.dom ? el : Roo.fly(el);
22674         if (!this.deltaSetXY) {
22675             var aCoord = [oCoord.x, oCoord.y];
22676             fly.setXY(aCoord);
22677             var newLeft = fly.getLeft(true);
22678             var newTop  = fly.getTop(true);
22679             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22680         } else {
22681             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22682         }
22683
22684         this.cachePosition(oCoord.x, oCoord.y);
22685         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22686         return oCoord;
22687     },
22688
22689     /**
22690      * Saves the most recent position so that we can reset the constraints and
22691      * tick marks on-demand.  We need to know this so that we can calculate the
22692      * number of pixels the element is offset from its original position.
22693      * @method cachePosition
22694      * @param iPageX the current x position (optional, this just makes it so we
22695      * don't have to look it up again)
22696      * @param iPageY the current y position (optional, this just makes it so we
22697      * don't have to look it up again)
22698      */
22699     cachePosition: function(iPageX, iPageY) {
22700         if (iPageX) {
22701             this.lastPageX = iPageX;
22702             this.lastPageY = iPageY;
22703         } else {
22704             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22705             this.lastPageX = aCoord[0];
22706             this.lastPageY = aCoord[1];
22707         }
22708     },
22709
22710     /**
22711      * Auto-scroll the window if the dragged object has been moved beyond the
22712      * visible window boundary.
22713      * @method autoScroll
22714      * @param {int} x the drag element's x position
22715      * @param {int} y the drag element's y position
22716      * @param {int} h the height of the drag element
22717      * @param {int} w the width of the drag element
22718      * @private
22719      */
22720     autoScroll: function(x, y, h, w) {
22721
22722         if (this.scroll) {
22723             // The client height
22724             var clientH = Roo.lib.Dom.getViewWidth();
22725
22726             // The client width
22727             var clientW = Roo.lib.Dom.getViewHeight();
22728
22729             // The amt scrolled down
22730             var st = this.DDM.getScrollTop();
22731
22732             // The amt scrolled right
22733             var sl = this.DDM.getScrollLeft();
22734
22735             // Location of the bottom of the element
22736             var bot = h + y;
22737
22738             // Location of the right of the element
22739             var right = w + x;
22740
22741             // The distance from the cursor to the bottom of the visible area,
22742             // adjusted so that we don't scroll if the cursor is beyond the
22743             // element drag constraints
22744             var toBot = (clientH + st - y - this.deltaY);
22745
22746             // The distance from the cursor to the right of the visible area
22747             var toRight = (clientW + sl - x - this.deltaX);
22748
22749
22750             // How close to the edge the cursor must be before we scroll
22751             // var thresh = (document.all) ? 100 : 40;
22752             var thresh = 40;
22753
22754             // How many pixels to scroll per autoscroll op.  This helps to reduce
22755             // clunky scrolling. IE is more sensitive about this ... it needs this
22756             // value to be higher.
22757             var scrAmt = (document.all) ? 80 : 30;
22758
22759             // Scroll down if we are near the bottom of the visible page and the
22760             // obj extends below the crease
22761             if ( bot > clientH && toBot < thresh ) {
22762                 window.scrollTo(sl, st + scrAmt);
22763             }
22764
22765             // Scroll up if the window is scrolled down and the top of the object
22766             // goes above the top border
22767             if ( y < st && st > 0 && y - st < thresh ) {
22768                 window.scrollTo(sl, st - scrAmt);
22769             }
22770
22771             // Scroll right if the obj is beyond the right border and the cursor is
22772             // near the border.
22773             if ( right > clientW && toRight < thresh ) {
22774                 window.scrollTo(sl + scrAmt, st);
22775             }
22776
22777             // Scroll left if the window has been scrolled to the right and the obj
22778             // extends past the left border
22779             if ( x < sl && sl > 0 && x - sl < thresh ) {
22780                 window.scrollTo(sl - scrAmt, st);
22781             }
22782         }
22783     },
22784
22785     /**
22786      * Finds the location the element should be placed if we want to move
22787      * it to where the mouse location less the click offset would place us.
22788      * @method getTargetCoord
22789      * @param {int} iPageX the X coordinate of the click
22790      * @param {int} iPageY the Y coordinate of the click
22791      * @return an object that contains the coordinates (Object.x and Object.y)
22792      * @private
22793      */
22794     getTargetCoord: function(iPageX, iPageY) {
22795
22796
22797         var x = iPageX - this.deltaX;
22798         var y = iPageY - this.deltaY;
22799
22800         if (this.constrainX) {
22801             if (x < this.minX) { x = this.minX; }
22802             if (x > this.maxX) { x = this.maxX; }
22803         }
22804
22805         if (this.constrainY) {
22806             if (y < this.minY) { y = this.minY; }
22807             if (y > this.maxY) { y = this.maxY; }
22808         }
22809
22810         x = this.getTick(x, this.xTicks);
22811         y = this.getTick(y, this.yTicks);
22812
22813
22814         return {x:x, y:y};
22815     },
22816
22817     /*
22818      * Sets up config options specific to this class. Overrides
22819      * Roo.dd.DragDrop, but all versions of this method through the
22820      * inheritance chain are called
22821      */
22822     applyConfig: function() {
22823         Roo.dd.DD.superclass.applyConfig.call(this);
22824         this.scroll = (this.config.scroll !== false);
22825     },
22826
22827     /*
22828      * Event that fires prior to the onMouseDown event.  Overrides
22829      * Roo.dd.DragDrop.
22830      */
22831     b4MouseDown: function(e) {
22832         // this.resetConstraints();
22833         this.autoOffset(e.getPageX(),
22834                             e.getPageY());
22835     },
22836
22837     /*
22838      * Event that fires prior to the onDrag event.  Overrides
22839      * Roo.dd.DragDrop.
22840      */
22841     b4Drag: function(e) {
22842         this.setDragElPos(e.getPageX(),
22843                             e.getPageY());
22844     },
22845
22846     toString: function() {
22847         return ("DD " + this.id);
22848     }
22849
22850     //////////////////////////////////////////////////////////////////////////
22851     // Debugging ygDragDrop events that can be overridden
22852     //////////////////////////////////////////////////////////////////////////
22853     /*
22854     startDrag: function(x, y) {
22855     },
22856
22857     onDrag: function(e) {
22858     },
22859
22860     onDragEnter: function(e, id) {
22861     },
22862
22863     onDragOver: function(e, id) {
22864     },
22865
22866     onDragOut: function(e, id) {
22867     },
22868
22869     onDragDrop: function(e, id) {
22870     },
22871
22872     endDrag: function(e) {
22873     }
22874
22875     */
22876
22877 });/*
22878  * Based on:
22879  * Ext JS Library 1.1.1
22880  * Copyright(c) 2006-2007, Ext JS, LLC.
22881  *
22882  * Originally Released Under LGPL - original licence link has changed is not relivant.
22883  *
22884  * Fork - LGPL
22885  * <script type="text/javascript">
22886  */
22887
22888 /**
22889  * @class Roo.dd.DDProxy
22890  * A DragDrop implementation that inserts an empty, bordered div into
22891  * the document that follows the cursor during drag operations.  At the time of
22892  * the click, the frame div is resized to the dimensions of the linked html
22893  * element, and moved to the exact location of the linked element.
22894  *
22895  * References to the "frame" element refer to the single proxy element that
22896  * was created to be dragged in place of all DDProxy elements on the
22897  * page.
22898  *
22899  * @extends Roo.dd.DD
22900  * @constructor
22901  * @param {String} id the id of the linked html element
22902  * @param {String} sGroup the group of related DragDrop objects
22903  * @param {object} config an object containing configurable attributes
22904  *                Valid properties for DDProxy in addition to those in DragDrop:
22905  *                   resizeFrame, centerFrame, dragElId
22906  */
22907 Roo.dd.DDProxy = function(id, sGroup, config) {
22908     if (id) {
22909         this.init(id, sGroup, config);
22910         this.initFrame();
22911     }
22912 };
22913
22914 /**
22915  * The default drag frame div id
22916  * @property Roo.dd.DDProxy.dragElId
22917  * @type String
22918  * @static
22919  */
22920 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22921
22922 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22923
22924     /**
22925      * By default we resize the drag frame to be the same size as the element
22926      * we want to drag (this is to get the frame effect).  We can turn it off
22927      * if we want a different behavior.
22928      * @property resizeFrame
22929      * @type boolean
22930      */
22931     resizeFrame: true,
22932
22933     /**
22934      * By default the frame is positioned exactly where the drag element is, so
22935      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22936      * you do not have constraints on the obj is to have the drag frame centered
22937      * around the cursor.  Set centerFrame to true for this effect.
22938      * @property centerFrame
22939      * @type boolean
22940      */
22941     centerFrame: false,
22942
22943     /**
22944      * Creates the proxy element if it does not yet exist
22945      * @method createFrame
22946      */
22947     createFrame: function() {
22948         var self = this;
22949         var body = document.body;
22950
22951         if (!body || !body.firstChild) {
22952             setTimeout( function() { self.createFrame(); }, 50 );
22953             return;
22954         }
22955
22956         var div = this.getDragEl();
22957
22958         if (!div) {
22959             div    = document.createElement("div");
22960             div.id = this.dragElId;
22961             var s  = div.style;
22962
22963             s.position   = "absolute";
22964             s.visibility = "hidden";
22965             s.cursor     = "move";
22966             s.border     = "2px solid #aaa";
22967             s.zIndex     = 999;
22968
22969             // appendChild can blow up IE if invoked prior to the window load event
22970             // while rendering a table.  It is possible there are other scenarios
22971             // that would cause this to happen as well.
22972             body.insertBefore(div, body.firstChild);
22973         }
22974     },
22975
22976     /**
22977      * Initialization for the drag frame element.  Must be called in the
22978      * constructor of all subclasses
22979      * @method initFrame
22980      */
22981     initFrame: function() {
22982         this.createFrame();
22983     },
22984
22985     applyConfig: function() {
22986         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22987
22988         this.resizeFrame = (this.config.resizeFrame !== false);
22989         this.centerFrame = (this.config.centerFrame);
22990         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22991     },
22992
22993     /**
22994      * Resizes the drag frame to the dimensions of the clicked object, positions
22995      * it over the object, and finally displays it
22996      * @method showFrame
22997      * @param {int} iPageX X click position
22998      * @param {int} iPageY Y click position
22999      * @private
23000      */
23001     showFrame: function(iPageX, iPageY) {
23002         var el = this.getEl();
23003         var dragEl = this.getDragEl();
23004         var s = dragEl.style;
23005
23006         this._resizeProxy();
23007
23008         if (this.centerFrame) {
23009             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23010                            Math.round(parseInt(s.height, 10)/2) );
23011         }
23012
23013         this.setDragElPos(iPageX, iPageY);
23014
23015         Roo.fly(dragEl).show();
23016     },
23017
23018     /**
23019      * The proxy is automatically resized to the dimensions of the linked
23020      * element when a drag is initiated, unless resizeFrame is set to false
23021      * @method _resizeProxy
23022      * @private
23023      */
23024     _resizeProxy: function() {
23025         if (this.resizeFrame) {
23026             var el = this.getEl();
23027             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23028         }
23029     },
23030
23031     // overrides Roo.dd.DragDrop
23032     b4MouseDown: function(e) {
23033         var x = e.getPageX();
23034         var y = e.getPageY();
23035         this.autoOffset(x, y);
23036         this.setDragElPos(x, y);
23037     },
23038
23039     // overrides Roo.dd.DragDrop
23040     b4StartDrag: function(x, y) {
23041         // show the drag frame
23042         this.showFrame(x, y);
23043     },
23044
23045     // overrides Roo.dd.DragDrop
23046     b4EndDrag: function(e) {
23047         Roo.fly(this.getDragEl()).hide();
23048     },
23049
23050     // overrides Roo.dd.DragDrop
23051     // By default we try to move the element to the last location of the frame.
23052     // This is so that the default behavior mirrors that of Roo.dd.DD.
23053     endDrag: function(e) {
23054
23055         var lel = this.getEl();
23056         var del = this.getDragEl();
23057
23058         // Show the drag frame briefly so we can get its position
23059         del.style.visibility = "";
23060
23061         this.beforeMove();
23062         // Hide the linked element before the move to get around a Safari
23063         // rendering bug.
23064         lel.style.visibility = "hidden";
23065         Roo.dd.DDM.moveToEl(lel, del);
23066         del.style.visibility = "hidden";
23067         lel.style.visibility = "";
23068
23069         this.afterDrag();
23070     },
23071
23072     beforeMove : function(){
23073
23074     },
23075
23076     afterDrag : function(){
23077
23078     },
23079
23080     toString: function() {
23081         return ("DDProxy " + this.id);
23082     }
23083
23084 });
23085 /*
23086  * Based on:
23087  * Ext JS Library 1.1.1
23088  * Copyright(c) 2006-2007, Ext JS, LLC.
23089  *
23090  * Originally Released Under LGPL - original licence link has changed is not relivant.
23091  *
23092  * Fork - LGPL
23093  * <script type="text/javascript">
23094  */
23095
23096  /**
23097  * @class Roo.dd.DDTarget
23098  * A DragDrop implementation that does not move, but can be a drop
23099  * target.  You would get the same result by simply omitting implementation
23100  * for the event callbacks, but this way we reduce the processing cost of the
23101  * event listener and the callbacks.
23102  * @extends Roo.dd.DragDrop
23103  * @constructor
23104  * @param {String} id the id of the element that is a drop target
23105  * @param {String} sGroup the group of related DragDrop objects
23106  * @param {object} config an object containing configurable attributes
23107  *                 Valid properties for DDTarget in addition to those in
23108  *                 DragDrop:
23109  *                    none
23110  */
23111 Roo.dd.DDTarget = function(id, sGroup, config) {
23112     if (id) {
23113         this.initTarget(id, sGroup, config);
23114     }
23115     if (config && (config.listeners || config.events)) { 
23116         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23117             listeners : config.listeners || {}, 
23118             events : config.events || {} 
23119         });    
23120     }
23121 };
23122
23123 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23124 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23125     toString: function() {
23126         return ("DDTarget " + this.id);
23127     }
23128 });
23129 /*
23130  * Based on:
23131  * Ext JS Library 1.1.1
23132  * Copyright(c) 2006-2007, Ext JS, LLC.
23133  *
23134  * Originally Released Under LGPL - original licence link has changed is not relivant.
23135  *
23136  * Fork - LGPL
23137  * <script type="text/javascript">
23138  */
23139  
23140
23141 /**
23142  * @class Roo.dd.ScrollManager
23143  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23144  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23145  * @static
23146  */
23147 Roo.dd.ScrollManager = function(){
23148     var ddm = Roo.dd.DragDropMgr;
23149     var els = {};
23150     var dragEl = null;
23151     var proc = {};
23152     
23153     
23154     
23155     var onStop = function(e){
23156         dragEl = null;
23157         clearProc();
23158     };
23159     
23160     var triggerRefresh = function(){
23161         if(ddm.dragCurrent){
23162              ddm.refreshCache(ddm.dragCurrent.groups);
23163         }
23164     };
23165     
23166     var doScroll = function(){
23167         if(ddm.dragCurrent){
23168             var dds = Roo.dd.ScrollManager;
23169             if(!dds.animate){
23170                 if(proc.el.scroll(proc.dir, dds.increment)){
23171                     triggerRefresh();
23172                 }
23173             }else{
23174                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23175             }
23176         }
23177     };
23178     
23179     var clearProc = function(){
23180         if(proc.id){
23181             clearInterval(proc.id);
23182         }
23183         proc.id = 0;
23184         proc.el = null;
23185         proc.dir = "";
23186     };
23187     
23188     var startProc = function(el, dir){
23189          Roo.log('scroll startproc');
23190         clearProc();
23191         proc.el = el;
23192         proc.dir = dir;
23193         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23194     };
23195     
23196     var onFire = function(e, isDrop){
23197        
23198         if(isDrop || !ddm.dragCurrent){ return; }
23199         var dds = Roo.dd.ScrollManager;
23200         if(!dragEl || dragEl != ddm.dragCurrent){
23201             dragEl = ddm.dragCurrent;
23202             // refresh regions on drag start
23203             dds.refreshCache();
23204         }
23205         
23206         var xy = Roo.lib.Event.getXY(e);
23207         var pt = new Roo.lib.Point(xy[0], xy[1]);
23208         for(var id in els){
23209             var el = els[id], r = el._region;
23210             if(r && r.contains(pt) && el.isScrollable()){
23211                 if(r.bottom - pt.y <= dds.thresh){
23212                     if(proc.el != el){
23213                         startProc(el, "down");
23214                     }
23215                     return;
23216                 }else if(r.right - pt.x <= dds.thresh){
23217                     if(proc.el != el){
23218                         startProc(el, "left");
23219                     }
23220                     return;
23221                 }else if(pt.y - r.top <= dds.thresh){
23222                     if(proc.el != el){
23223                         startProc(el, "up");
23224                     }
23225                     return;
23226                 }else if(pt.x - r.left <= dds.thresh){
23227                     if(proc.el != el){
23228                         startProc(el, "right");
23229                     }
23230                     return;
23231                 }
23232             }
23233         }
23234         clearProc();
23235     };
23236     
23237     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23238     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23239     
23240     return {
23241         /**
23242          * Registers new overflow element(s) to auto scroll
23243          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23244          */
23245         register : function(el){
23246             if(el instanceof Array){
23247                 for(var i = 0, len = el.length; i < len; i++) {
23248                         this.register(el[i]);
23249                 }
23250             }else{
23251                 el = Roo.get(el);
23252                 els[el.id] = el;
23253             }
23254             Roo.dd.ScrollManager.els = els;
23255         },
23256         
23257         /**
23258          * Unregisters overflow element(s) so they are no longer scrolled
23259          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23260          */
23261         unregister : function(el){
23262             if(el instanceof Array){
23263                 for(var i = 0, len = el.length; i < len; i++) {
23264                         this.unregister(el[i]);
23265                 }
23266             }else{
23267                 el = Roo.get(el);
23268                 delete els[el.id];
23269             }
23270         },
23271         
23272         /**
23273          * The number of pixels from the edge of a container the pointer needs to be to 
23274          * trigger scrolling (defaults to 25)
23275          * @type Number
23276          */
23277         thresh : 25,
23278         
23279         /**
23280          * The number of pixels to scroll in each scroll increment (defaults to 50)
23281          * @type Number
23282          */
23283         increment : 100,
23284         
23285         /**
23286          * The frequency of scrolls in milliseconds (defaults to 500)
23287          * @type Number
23288          */
23289         frequency : 500,
23290         
23291         /**
23292          * True to animate the scroll (defaults to true)
23293          * @type Boolean
23294          */
23295         animate: true,
23296         
23297         /**
23298          * The animation duration in seconds - 
23299          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23300          * @type Number
23301          */
23302         animDuration: .4,
23303         
23304         /**
23305          * Manually trigger a cache refresh.
23306          */
23307         refreshCache : function(){
23308             for(var id in els){
23309                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23310                     els[id]._region = els[id].getRegion();
23311                 }
23312             }
23313         }
23314     };
23315 }();/*
23316  * Based on:
23317  * Ext JS Library 1.1.1
23318  * Copyright(c) 2006-2007, Ext JS, LLC.
23319  *
23320  * Originally Released Under LGPL - original licence link has changed is not relivant.
23321  *
23322  * Fork - LGPL
23323  * <script type="text/javascript">
23324  */
23325  
23326
23327 /**
23328  * @class Roo.dd.Registry
23329  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23330  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23331  * @static
23332  */
23333 Roo.dd.Registry = function(){
23334     var elements = {}; 
23335     var handles = {}; 
23336     var autoIdSeed = 0;
23337
23338     var getId = function(el, autogen){
23339         if(typeof el == "string"){
23340             return el;
23341         }
23342         var id = el.id;
23343         if(!id && autogen !== false){
23344             id = "roodd-" + (++autoIdSeed);
23345             el.id = id;
23346         }
23347         return id;
23348     };
23349     
23350     return {
23351     /**
23352      * Register a drag drop element
23353      * @param {String|HTMLElement} element The id or DOM node to register
23354      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23355      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23356      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23357      * populated in the data object (if applicable):
23358      * <pre>
23359 Value      Description<br />
23360 ---------  ------------------------------------------<br />
23361 handles    Array of DOM nodes that trigger dragging<br />
23362            for the element being registered<br />
23363 isHandle   True if the element passed in triggers<br />
23364            dragging itself, else false
23365 </pre>
23366      */
23367         register : function(el, data){
23368             data = data || {};
23369             if(typeof el == "string"){
23370                 el = document.getElementById(el);
23371             }
23372             data.ddel = el;
23373             elements[getId(el)] = data;
23374             if(data.isHandle !== false){
23375                 handles[data.ddel.id] = data;
23376             }
23377             if(data.handles){
23378                 var hs = data.handles;
23379                 for(var i = 0, len = hs.length; i < len; i++){
23380                         handles[getId(hs[i])] = data;
23381                 }
23382             }
23383         },
23384
23385     /**
23386      * Unregister a drag drop element
23387      * @param {String|HTMLElement}  element The id or DOM node to unregister
23388      */
23389         unregister : function(el){
23390             var id = getId(el, false);
23391             var data = elements[id];
23392             if(data){
23393                 delete elements[id];
23394                 if(data.handles){
23395                     var hs = data.handles;
23396                     for(var i = 0, len = hs.length; i < len; i++){
23397                         delete handles[getId(hs[i], false)];
23398                     }
23399                 }
23400             }
23401         },
23402
23403     /**
23404      * Returns the handle registered for a DOM Node by id
23405      * @param {String|HTMLElement} id The DOM node or id to look up
23406      * @return {Object} handle The custom handle data
23407      */
23408         getHandle : function(id){
23409             if(typeof id != "string"){ // must be element?
23410                 id = id.id;
23411             }
23412             return handles[id];
23413         },
23414
23415     /**
23416      * Returns the handle that is registered for the DOM node that is the target of the event
23417      * @param {Event} e The event
23418      * @return {Object} handle The custom handle data
23419      */
23420         getHandleFromEvent : function(e){
23421             var t = Roo.lib.Event.getTarget(e);
23422             return t ? handles[t.id] : null;
23423         },
23424
23425     /**
23426      * Returns a custom data object that is registered for a DOM node by id
23427      * @param {String|HTMLElement} id The DOM node or id to look up
23428      * @return {Object} data The custom data
23429      */
23430         getTarget : function(id){
23431             if(typeof id != "string"){ // must be element?
23432                 id = id.id;
23433             }
23434             return elements[id];
23435         },
23436
23437     /**
23438      * Returns a custom data object that is registered for the DOM node that is the target of the event
23439      * @param {Event} e The event
23440      * @return {Object} data The custom data
23441      */
23442         getTargetFromEvent : function(e){
23443             var t = Roo.lib.Event.getTarget(e);
23444             return t ? elements[t.id] || handles[t.id] : null;
23445         }
23446     };
23447 }();/*
23448  * Based on:
23449  * Ext JS Library 1.1.1
23450  * Copyright(c) 2006-2007, Ext JS, LLC.
23451  *
23452  * Originally Released Under LGPL - original licence link has changed is not relivant.
23453  *
23454  * Fork - LGPL
23455  * <script type="text/javascript">
23456  */
23457  
23458
23459 /**
23460  * @class Roo.dd.StatusProxy
23461  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23462  * default drag proxy used by all Roo.dd components.
23463  * @constructor
23464  * @param {Object} config
23465  */
23466 Roo.dd.StatusProxy = function(config){
23467     Roo.apply(this, config);
23468     this.id = this.id || Roo.id();
23469     this.el = new Roo.Layer({
23470         dh: {
23471             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23472                 {tag: "div", cls: "x-dd-drop-icon"},
23473                 {tag: "div", cls: "x-dd-drag-ghost"}
23474             ]
23475         }, 
23476         shadow: !config || config.shadow !== false
23477     });
23478     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23479     this.dropStatus = this.dropNotAllowed;
23480 };
23481
23482 Roo.dd.StatusProxy.prototype = {
23483     /**
23484      * @cfg {String} dropAllowed
23485      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23486      */
23487     dropAllowed : "x-dd-drop-ok",
23488     /**
23489      * @cfg {String} dropNotAllowed
23490      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23491      */
23492     dropNotAllowed : "x-dd-drop-nodrop",
23493
23494     /**
23495      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23496      * over the current target element.
23497      * @param {String} cssClass The css class for the new drop status indicator image
23498      */
23499     setStatus : function(cssClass){
23500         cssClass = cssClass || this.dropNotAllowed;
23501         if(this.dropStatus != cssClass){
23502             this.el.replaceClass(this.dropStatus, cssClass);
23503             this.dropStatus = cssClass;
23504         }
23505     },
23506
23507     /**
23508      * Resets the status indicator to the default dropNotAllowed value
23509      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23510      */
23511     reset : function(clearGhost){
23512         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23513         this.dropStatus = this.dropNotAllowed;
23514         if(clearGhost){
23515             this.ghost.update("");
23516         }
23517     },
23518
23519     /**
23520      * Updates the contents of the ghost element
23521      * @param {String} html The html that will replace the current innerHTML of the ghost element
23522      */
23523     update : function(html){
23524         if(typeof html == "string"){
23525             this.ghost.update(html);
23526         }else{
23527             this.ghost.update("");
23528             html.style.margin = "0";
23529             this.ghost.dom.appendChild(html);
23530         }
23531         // ensure float = none set?? cant remember why though.
23532         var el = this.ghost.dom.firstChild;
23533                 if(el){
23534                         Roo.fly(el).setStyle('float', 'none');
23535                 }
23536     },
23537     
23538     /**
23539      * Returns the underlying proxy {@link Roo.Layer}
23540      * @return {Roo.Layer} el
23541     */
23542     getEl : function(){
23543         return this.el;
23544     },
23545
23546     /**
23547      * Returns the ghost element
23548      * @return {Roo.Element} el
23549      */
23550     getGhost : function(){
23551         return this.ghost;
23552     },
23553
23554     /**
23555      * Hides the proxy
23556      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23557      */
23558     hide : function(clear){
23559         this.el.hide();
23560         if(clear){
23561             this.reset(true);
23562         }
23563     },
23564
23565     /**
23566      * Stops the repair animation if it's currently running
23567      */
23568     stop : function(){
23569         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23570             this.anim.stop();
23571         }
23572     },
23573
23574     /**
23575      * Displays this proxy
23576      */
23577     show : function(){
23578         this.el.show();
23579     },
23580
23581     /**
23582      * Force the Layer to sync its shadow and shim positions to the element
23583      */
23584     sync : function(){
23585         this.el.sync();
23586     },
23587
23588     /**
23589      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23590      * invalid drop operation by the item being dragged.
23591      * @param {Array} xy The XY position of the element ([x, y])
23592      * @param {Function} callback The function to call after the repair is complete
23593      * @param {Object} scope The scope in which to execute the callback
23594      */
23595     repair : function(xy, callback, scope){
23596         this.callback = callback;
23597         this.scope = scope;
23598         if(xy && this.animRepair !== false){
23599             this.el.addClass("x-dd-drag-repair");
23600             this.el.hideUnders(true);
23601             this.anim = this.el.shift({
23602                 duration: this.repairDuration || .5,
23603                 easing: 'easeOut',
23604                 xy: xy,
23605                 stopFx: true,
23606                 callback: this.afterRepair,
23607                 scope: this
23608             });
23609         }else{
23610             this.afterRepair();
23611         }
23612     },
23613
23614     // private
23615     afterRepair : function(){
23616         this.hide(true);
23617         if(typeof this.callback == "function"){
23618             this.callback.call(this.scope || this);
23619         }
23620         this.callback = null;
23621         this.scope = null;
23622     }
23623 };/*
23624  * Based on:
23625  * Ext JS Library 1.1.1
23626  * Copyright(c) 2006-2007, Ext JS, LLC.
23627  *
23628  * Originally Released Under LGPL - original licence link has changed is not relivant.
23629  *
23630  * Fork - LGPL
23631  * <script type="text/javascript">
23632  */
23633
23634 /**
23635  * @class Roo.dd.DragSource
23636  * @extends Roo.dd.DDProxy
23637  * A simple class that provides the basic implementation needed to make any element draggable.
23638  * @constructor
23639  * @param {String/HTMLElement/Element} el The container element
23640  * @param {Object} config
23641  */
23642 Roo.dd.DragSource = function(el, config){
23643     this.el = Roo.get(el);
23644     this.dragData = {};
23645     
23646     Roo.apply(this, config);
23647     
23648     if(!this.proxy){
23649         this.proxy = new Roo.dd.StatusProxy();
23650     }
23651
23652     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23653           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23654     
23655     this.dragging = false;
23656 };
23657
23658 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23659     /**
23660      * @cfg {String} dropAllowed
23661      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23662      */
23663     dropAllowed : "x-dd-drop-ok",
23664     /**
23665      * @cfg {String} dropNotAllowed
23666      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23667      */
23668     dropNotAllowed : "x-dd-drop-nodrop",
23669
23670     /**
23671      * Returns the data object associated with this drag source
23672      * @return {Object} data An object containing arbitrary data
23673      */
23674     getDragData : function(e){
23675         return this.dragData;
23676     },
23677
23678     // private
23679     onDragEnter : function(e, id){
23680         var target = Roo.dd.DragDropMgr.getDDById(id);
23681         this.cachedTarget = target;
23682         if(this.beforeDragEnter(target, e, id) !== false){
23683             if(target.isNotifyTarget){
23684                 var status = target.notifyEnter(this, e, this.dragData);
23685                 this.proxy.setStatus(status);
23686             }else{
23687                 this.proxy.setStatus(this.dropAllowed);
23688             }
23689             
23690             if(this.afterDragEnter){
23691                 /**
23692                  * An empty function by default, but provided so that you can perform a custom action
23693                  * when the dragged item enters the drop target by providing an implementation.
23694                  * @param {Roo.dd.DragDrop} target The drop target
23695                  * @param {Event} e The event object
23696                  * @param {String} id The id of the dragged element
23697                  * @method afterDragEnter
23698                  */
23699                 this.afterDragEnter(target, e, id);
23700             }
23701         }
23702     },
23703
23704     /**
23705      * An empty function by default, but provided so that you can perform a custom action
23706      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23707      * @param {Roo.dd.DragDrop} target The drop target
23708      * @param {Event} e The event object
23709      * @param {String} id The id of the dragged element
23710      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23711      */
23712     beforeDragEnter : function(target, e, id){
23713         return true;
23714     },
23715
23716     // private
23717     alignElWithMouse: function() {
23718         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23719         this.proxy.sync();
23720     },
23721
23722     // private
23723     onDragOver : function(e, id){
23724         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23725         if(this.beforeDragOver(target, e, id) !== false){
23726             if(target.isNotifyTarget){
23727                 var status = target.notifyOver(this, e, this.dragData);
23728                 this.proxy.setStatus(status);
23729             }
23730
23731             if(this.afterDragOver){
23732                 /**
23733                  * An empty function by default, but provided so that you can perform a custom action
23734                  * while the dragged item is over the drop target by providing an implementation.
23735                  * @param {Roo.dd.DragDrop} target The drop target
23736                  * @param {Event} e The event object
23737                  * @param {String} id The id of the dragged element
23738                  * @method afterDragOver
23739                  */
23740                 this.afterDragOver(target, e, id);
23741             }
23742         }
23743     },
23744
23745     /**
23746      * An empty function by default, but provided so that you can perform a custom action
23747      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23748      * @param {Roo.dd.DragDrop} target The drop target
23749      * @param {Event} e The event object
23750      * @param {String} id The id of the dragged element
23751      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23752      */
23753     beforeDragOver : function(target, e, id){
23754         return true;
23755     },
23756
23757     // private
23758     onDragOut : function(e, id){
23759         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23760         if(this.beforeDragOut(target, e, id) !== false){
23761             if(target.isNotifyTarget){
23762                 target.notifyOut(this, e, this.dragData);
23763             }
23764             this.proxy.reset();
23765             if(this.afterDragOut){
23766                 /**
23767                  * An empty function by default, but provided so that you can perform a custom action
23768                  * after the dragged item is dragged out of the target without dropping.
23769                  * @param {Roo.dd.DragDrop} target The drop target
23770                  * @param {Event} e The event object
23771                  * @param {String} id The id of the dragged element
23772                  * @method afterDragOut
23773                  */
23774                 this.afterDragOut(target, e, id);
23775             }
23776         }
23777         this.cachedTarget = null;
23778     },
23779
23780     /**
23781      * An empty function by default, but provided so that you can perform a custom action before the dragged
23782      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23783      * @param {Roo.dd.DragDrop} target The drop target
23784      * @param {Event} e The event object
23785      * @param {String} id The id of the dragged element
23786      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23787      */
23788     beforeDragOut : function(target, e, id){
23789         return true;
23790     },
23791     
23792     // private
23793     onDragDrop : function(e, id){
23794         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23795         if(this.beforeDragDrop(target, e, id) !== false){
23796             if(target.isNotifyTarget){
23797                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23798                     this.onValidDrop(target, e, id);
23799                 }else{
23800                     this.onInvalidDrop(target, e, id);
23801                 }
23802             }else{
23803                 this.onValidDrop(target, e, id);
23804             }
23805             
23806             if(this.afterDragDrop){
23807                 /**
23808                  * An empty function by default, but provided so that you can perform a custom action
23809                  * after a valid drag drop has occurred by providing an implementation.
23810                  * @param {Roo.dd.DragDrop} target The drop target
23811                  * @param {Event} e The event object
23812                  * @param {String} id The id of the dropped element
23813                  * @method afterDragDrop
23814                  */
23815                 this.afterDragDrop(target, e, id);
23816             }
23817         }
23818         delete this.cachedTarget;
23819     },
23820
23821     /**
23822      * An empty function by default, but provided so that you can perform a custom action before the dragged
23823      * item is dropped onto the target and optionally cancel the onDragDrop.
23824      * @param {Roo.dd.DragDrop} target The drop target
23825      * @param {Event} e The event object
23826      * @param {String} id The id of the dragged element
23827      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23828      */
23829     beforeDragDrop : function(target, e, id){
23830         return true;
23831     },
23832
23833     // private
23834     onValidDrop : function(target, e, id){
23835         this.hideProxy();
23836         if(this.afterValidDrop){
23837             /**
23838              * An empty function by default, but provided so that you can perform a custom action
23839              * after a valid drop has occurred by providing an implementation.
23840              * @param {Object} target The target DD 
23841              * @param {Event} e The event object
23842              * @param {String} id The id of the dropped element
23843              * @method afterInvalidDrop
23844              */
23845             this.afterValidDrop(target, e, id);
23846         }
23847     },
23848
23849     // private
23850     getRepairXY : function(e, data){
23851         return this.el.getXY();  
23852     },
23853
23854     // private
23855     onInvalidDrop : function(target, e, id){
23856         this.beforeInvalidDrop(target, e, id);
23857         if(this.cachedTarget){
23858             if(this.cachedTarget.isNotifyTarget){
23859                 this.cachedTarget.notifyOut(this, e, this.dragData);
23860             }
23861             this.cacheTarget = null;
23862         }
23863         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23864
23865         if(this.afterInvalidDrop){
23866             /**
23867              * An empty function by default, but provided so that you can perform a custom action
23868              * after an invalid drop has occurred by providing an implementation.
23869              * @param {Event} e The event object
23870              * @param {String} id The id of the dropped element
23871              * @method afterInvalidDrop
23872              */
23873             this.afterInvalidDrop(e, id);
23874         }
23875     },
23876
23877     // private
23878     afterRepair : function(){
23879         if(Roo.enableFx){
23880             this.el.highlight(this.hlColor || "c3daf9");
23881         }
23882         this.dragging = false;
23883     },
23884
23885     /**
23886      * An empty function by default, but provided so that you can perform a custom action after an invalid
23887      * drop has occurred.
23888      * @param {Roo.dd.DragDrop} target The drop target
23889      * @param {Event} e The event object
23890      * @param {String} id The id of the dragged element
23891      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23892      */
23893     beforeInvalidDrop : function(target, e, id){
23894         return true;
23895     },
23896
23897     // private
23898     handleMouseDown : function(e){
23899         if(this.dragging) {
23900             return;
23901         }
23902         var data = this.getDragData(e);
23903         if(data && this.onBeforeDrag(data, e) !== false){
23904             this.dragData = data;
23905             this.proxy.stop();
23906             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23907         } 
23908     },
23909
23910     /**
23911      * An empty function by default, but provided so that you can perform a custom action before the initial
23912      * drag event begins and optionally cancel it.
23913      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23914      * @param {Event} e The event object
23915      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23916      */
23917     onBeforeDrag : function(data, e){
23918         return true;
23919     },
23920
23921     /**
23922      * An empty function by default, but provided so that you can perform a custom action once the initial
23923      * drag event has begun.  The drag cannot be canceled from this function.
23924      * @param {Number} x The x position of the click on the dragged object
23925      * @param {Number} y The y position of the click on the dragged object
23926      */
23927     onStartDrag : Roo.emptyFn,
23928
23929     // private - YUI override
23930     startDrag : function(x, y){
23931         this.proxy.reset();
23932         this.dragging = true;
23933         this.proxy.update("");
23934         this.onInitDrag(x, y);
23935         this.proxy.show();
23936     },
23937
23938     // private
23939     onInitDrag : function(x, y){
23940         var clone = this.el.dom.cloneNode(true);
23941         clone.id = Roo.id(); // prevent duplicate ids
23942         this.proxy.update(clone);
23943         this.onStartDrag(x, y);
23944         return true;
23945     },
23946
23947     /**
23948      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23949      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23950      */
23951     getProxy : function(){
23952         return this.proxy;  
23953     },
23954
23955     /**
23956      * Hides the drag source's {@link Roo.dd.StatusProxy}
23957      */
23958     hideProxy : function(){
23959         this.proxy.hide();  
23960         this.proxy.reset(true);
23961         this.dragging = false;
23962     },
23963
23964     // private
23965     triggerCacheRefresh : function(){
23966         Roo.dd.DDM.refreshCache(this.groups);
23967     },
23968
23969     // private - override to prevent hiding
23970     b4EndDrag: function(e) {
23971     },
23972
23973     // private - override to prevent moving
23974     endDrag : function(e){
23975         this.onEndDrag(this.dragData, e);
23976     },
23977
23978     // private
23979     onEndDrag : function(data, e){
23980     },
23981     
23982     // private - pin to cursor
23983     autoOffset : function(x, y) {
23984         this.setDelta(-12, -20);
23985     }    
23986 });/*
23987  * Based on:
23988  * Ext JS Library 1.1.1
23989  * Copyright(c) 2006-2007, Ext JS, LLC.
23990  *
23991  * Originally Released Under LGPL - original licence link has changed is not relivant.
23992  *
23993  * Fork - LGPL
23994  * <script type="text/javascript">
23995  */
23996
23997
23998 /**
23999  * @class Roo.dd.DropTarget
24000  * @extends Roo.dd.DDTarget
24001  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24002  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24003  * @constructor
24004  * @param {String/HTMLElement/Element} el The container element
24005  * @param {Object} config
24006  */
24007 Roo.dd.DropTarget = function(el, config){
24008     this.el = Roo.get(el);
24009     
24010     var listeners = false; ;
24011     if (config && config.listeners) {
24012         listeners= config.listeners;
24013         delete config.listeners;
24014     }
24015     Roo.apply(this, config);
24016     
24017     if(this.containerScroll){
24018         Roo.dd.ScrollManager.register(this.el);
24019     }
24020     this.addEvents( {
24021          /**
24022          * @scope Roo.dd.DropTarget
24023          */
24024          
24025          /**
24026          * @event enter
24027          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24028          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24029          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24030          * 
24031          * IMPORTANT : it should set  this.valid to true|false
24032          * 
24033          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24034          * @param {Event} e The event
24035          * @param {Object} data An object containing arbitrary data supplied by the drag source
24036          */
24037         "enter" : true,
24038         
24039          /**
24040          * @event over
24041          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24042          * This method will be called on every mouse movement while the drag source is over the drop target.
24043          * This default implementation simply returns the dropAllowed config value.
24044          * 
24045          * IMPORTANT : it should set  this.valid to true|false
24046          * 
24047          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24048          * @param {Event} e The event
24049          * @param {Object} data An object containing arbitrary data supplied by the drag source
24050          
24051          */
24052         "over" : true,
24053         /**
24054          * @event out
24055          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24056          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24057          * overClass (if any) from the drop element.
24058          * 
24059          * 
24060          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24061          * @param {Event} e The event
24062          * @param {Object} data An object containing arbitrary data supplied by the drag source
24063          */
24064          "out" : true,
24065          
24066         /**
24067          * @event drop
24068          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24069          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24070          * implementation that does something to process the drop event and returns true so that the drag source's
24071          * repair action does not run.
24072          * 
24073          * IMPORTANT : it should set this.success
24074          * 
24075          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24076          * @param {Event} e The event
24077          * @param {Object} data An object containing arbitrary data supplied by the drag source
24078         */
24079          "drop" : true
24080     });
24081             
24082      
24083     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24084         this.el.dom, 
24085         this.ddGroup || this.group,
24086         {
24087             isTarget: true,
24088             listeners : listeners || {} 
24089            
24090         
24091         }
24092     );
24093
24094 };
24095
24096 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24097     /**
24098      * @cfg {String} overClass
24099      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24100      */
24101      /**
24102      * @cfg {String} ddGroup
24103      * The drag drop group to handle drop events for
24104      */
24105      
24106     /**
24107      * @cfg {String} dropAllowed
24108      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24109      */
24110     dropAllowed : "x-dd-drop-ok",
24111     /**
24112      * @cfg {String} dropNotAllowed
24113      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24114      */
24115     dropNotAllowed : "x-dd-drop-nodrop",
24116     /**
24117      * @cfg {boolean} success
24118      * set this after drop listener.. 
24119      */
24120     success : false,
24121     /**
24122      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24123      * if the drop point is valid for over/enter..
24124      */
24125     valid : false,
24126     // private
24127     isTarget : true,
24128
24129     // private
24130     isNotifyTarget : true,
24131     
24132     /**
24133      * @hide
24134      */
24135     notifyEnter : function(dd, e, data)
24136     {
24137         this.valid = true;
24138         this.fireEvent('enter', dd, e, data);
24139         if(this.overClass){
24140             this.el.addClass(this.overClass);
24141         }
24142         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24143             this.valid ? this.dropAllowed : this.dropNotAllowed
24144         );
24145     },
24146
24147     /**
24148      * @hide
24149      */
24150     notifyOver : function(dd, e, data)
24151     {
24152         this.valid = true;
24153         this.fireEvent('over', dd, e, data);
24154         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24155             this.valid ? this.dropAllowed : this.dropNotAllowed
24156         );
24157     },
24158
24159     /**
24160      * @hide
24161      */
24162     notifyOut : function(dd, e, data)
24163     {
24164         this.fireEvent('out', dd, e, data);
24165         if(this.overClass){
24166             this.el.removeClass(this.overClass);
24167         }
24168     },
24169
24170     /**
24171      * @hide
24172      */
24173     notifyDrop : function(dd, e, data)
24174     {
24175         this.success = false;
24176         this.fireEvent('drop', dd, e, data);
24177         return this.success;
24178     }
24179 });/*
24180  * Based on:
24181  * Ext JS Library 1.1.1
24182  * Copyright(c) 2006-2007, Ext JS, LLC.
24183  *
24184  * Originally Released Under LGPL - original licence link has changed is not relivant.
24185  *
24186  * Fork - LGPL
24187  * <script type="text/javascript">
24188  */
24189
24190
24191 /**
24192  * @class Roo.dd.DragZone
24193  * @extends Roo.dd.DragSource
24194  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24195  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24196  * @constructor
24197  * @param {String/HTMLElement/Element} el The container element
24198  * @param {Object} config
24199  */
24200 Roo.dd.DragZone = function(el, config){
24201     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24202     if(this.containerScroll){
24203         Roo.dd.ScrollManager.register(this.el);
24204     }
24205 };
24206
24207 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24208     /**
24209      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24210      * for auto scrolling during drag operations.
24211      */
24212     /**
24213      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24214      * method after a failed drop (defaults to "c3daf9" - light blue)
24215      */
24216
24217     /**
24218      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24219      * for a valid target to drag based on the mouse down. Override this method
24220      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24221      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24222      * @param {EventObject} e The mouse down event
24223      * @return {Object} The dragData
24224      */
24225     getDragData : function(e){
24226         return Roo.dd.Registry.getHandleFromEvent(e);
24227     },
24228     
24229     /**
24230      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24231      * this.dragData.ddel
24232      * @param {Number} x The x position of the click on the dragged object
24233      * @param {Number} y The y position of the click on the dragged object
24234      * @return {Boolean} true to continue the drag, false to cancel
24235      */
24236     onInitDrag : function(x, y){
24237         this.proxy.update(this.dragData.ddel.cloneNode(true));
24238         this.onStartDrag(x, y);
24239         return true;
24240     },
24241     
24242     /**
24243      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24244      */
24245     afterRepair : function(){
24246         if(Roo.enableFx){
24247             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24248         }
24249         this.dragging = false;
24250     },
24251
24252     /**
24253      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24254      * the XY of this.dragData.ddel
24255      * @param {EventObject} e The mouse up event
24256      * @return {Array} The xy location (e.g. [100, 200])
24257      */
24258     getRepairXY : function(e){
24259         return Roo.Element.fly(this.dragData.ddel).getXY();  
24260     }
24261 });/*
24262  * Based on:
24263  * Ext JS Library 1.1.1
24264  * Copyright(c) 2006-2007, Ext JS, LLC.
24265  *
24266  * Originally Released Under LGPL - original licence link has changed is not relivant.
24267  *
24268  * Fork - LGPL
24269  * <script type="text/javascript">
24270  */
24271 /**
24272  * @class Roo.dd.DropZone
24273  * @extends Roo.dd.DropTarget
24274  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24275  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24276  * @constructor
24277  * @param {String/HTMLElement/Element} el The container element
24278  * @param {Object} config
24279  */
24280 Roo.dd.DropZone = function(el, config){
24281     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24282 };
24283
24284 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24285     /**
24286      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24287      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24288      * provide your own custom lookup.
24289      * @param {Event} e The event
24290      * @return {Object} data The custom data
24291      */
24292     getTargetFromEvent : function(e){
24293         return Roo.dd.Registry.getTargetFromEvent(e);
24294     },
24295
24296     /**
24297      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24298      * that it has registered.  This method has no default implementation and should be overridden to provide
24299      * node-specific processing if necessary.
24300      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24301      * {@link #getTargetFromEvent} for this node)
24302      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24303      * @param {Event} e The event
24304      * @param {Object} data An object containing arbitrary data supplied by the drag source
24305      */
24306     onNodeEnter : function(n, dd, e, data){
24307         
24308     },
24309
24310     /**
24311      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24312      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24313      * overridden to provide the proper feedback.
24314      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24315      * {@link #getTargetFromEvent} for this node)
24316      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24317      * @param {Event} e The event
24318      * @param {Object} data An object containing arbitrary data supplied by the drag source
24319      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24320      * underlying {@link Roo.dd.StatusProxy} can be updated
24321      */
24322     onNodeOver : function(n, dd, e, data){
24323         return this.dropAllowed;
24324     },
24325
24326     /**
24327      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24328      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24329      * node-specific processing if necessary.
24330      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24331      * {@link #getTargetFromEvent} for this node)
24332      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24333      * @param {Event} e The event
24334      * @param {Object} data An object containing arbitrary data supplied by the drag source
24335      */
24336     onNodeOut : function(n, dd, e, data){
24337         
24338     },
24339
24340     /**
24341      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24342      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24343      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24344      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24345      * {@link #getTargetFromEvent} for this node)
24346      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24347      * @param {Event} e The event
24348      * @param {Object} data An object containing arbitrary data supplied by the drag source
24349      * @return {Boolean} True if the drop was valid, else false
24350      */
24351     onNodeDrop : function(n, dd, e, data){
24352         return false;
24353     },
24354
24355     /**
24356      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24357      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24358      * it should be overridden to provide the proper feedback if necessary.
24359      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24360      * @param {Event} e The event
24361      * @param {Object} data An object containing arbitrary data supplied by the drag source
24362      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24363      * underlying {@link Roo.dd.StatusProxy} can be updated
24364      */
24365     onContainerOver : function(dd, e, data){
24366         return this.dropNotAllowed;
24367     },
24368
24369     /**
24370      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24371      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24372      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24373      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24374      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24375      * @param {Event} e The event
24376      * @param {Object} data An object containing arbitrary data supplied by the drag source
24377      * @return {Boolean} True if the drop was valid, else false
24378      */
24379     onContainerDrop : function(dd, e, data){
24380         return false;
24381     },
24382
24383     /**
24384      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24385      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24386      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24387      * you should override this method and provide a custom implementation.
24388      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24389      * @param {Event} e The event
24390      * @param {Object} data An object containing arbitrary data supplied by the drag source
24391      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24392      * underlying {@link Roo.dd.StatusProxy} can be updated
24393      */
24394     notifyEnter : function(dd, e, data){
24395         return this.dropNotAllowed;
24396     },
24397
24398     /**
24399      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24400      * This method will be called on every mouse movement while the drag source is over the drop zone.
24401      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24402      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24403      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24404      * registered node, it will call {@link #onContainerOver}.
24405      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24406      * @param {Event} e The event
24407      * @param {Object} data An object containing arbitrary data supplied by the drag source
24408      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24409      * underlying {@link Roo.dd.StatusProxy} can be updated
24410      */
24411     notifyOver : function(dd, e, data){
24412         var n = this.getTargetFromEvent(e);
24413         if(!n){ // not over valid drop target
24414             if(this.lastOverNode){
24415                 this.onNodeOut(this.lastOverNode, dd, e, data);
24416                 this.lastOverNode = null;
24417             }
24418             return this.onContainerOver(dd, e, data);
24419         }
24420         if(this.lastOverNode != n){
24421             if(this.lastOverNode){
24422                 this.onNodeOut(this.lastOverNode, dd, e, data);
24423             }
24424             this.onNodeEnter(n, dd, e, data);
24425             this.lastOverNode = n;
24426         }
24427         return this.onNodeOver(n, dd, e, data);
24428     },
24429
24430     /**
24431      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24432      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24433      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24434      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24435      * @param {Event} e The event
24436      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24437      */
24438     notifyOut : function(dd, e, data){
24439         if(this.lastOverNode){
24440             this.onNodeOut(this.lastOverNode, dd, e, data);
24441             this.lastOverNode = null;
24442         }
24443     },
24444
24445     /**
24446      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24447      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24448      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24449      * otherwise it will call {@link #onContainerDrop}.
24450      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24451      * @param {Event} e The event
24452      * @param {Object} data An object containing arbitrary data supplied by the drag source
24453      * @return {Boolean} True if the drop was valid, else false
24454      */
24455     notifyDrop : function(dd, e, data){
24456         if(this.lastOverNode){
24457             this.onNodeOut(this.lastOverNode, dd, e, data);
24458             this.lastOverNode = null;
24459         }
24460         var n = this.getTargetFromEvent(e);
24461         return n ?
24462             this.onNodeDrop(n, dd, e, data) :
24463             this.onContainerDrop(dd, e, data);
24464     },
24465
24466     // private
24467     triggerCacheRefresh : function(){
24468         Roo.dd.DDM.refreshCache(this.groups);
24469     }  
24470 });